有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。
标签:做了 printf 有一个 display bool 入队 poi2008 考试 scan
有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。
输入n人数<1000000 每个人的aim
你要求最后死亡数目的最小和最大可能
8
2 3 2 2 6 7 8 5
3 5
本次考试最后一个题,被老师评论称难炸了……然而貌似不那么难,但你绝对打不A。
这道题只能怪我代码能力太弱,该想到的都想到了,然而还是华丽丽的爆了0。
首先让我们先明确几条性质来帮助我们做题:
为了方便,我们直接去求活着的人数,反正人不是活着就是死了废话。
先说死的人最少,那么入度为0的人一定活下来了,因此我们用队列慢慢往上爬即可,只要队列中的人他所杀的人要杀的人没人杀他了,那么他也可以入队。至于没人指向的环嘛,上面说了。
死的最多的人就是让人们从树顶从上往下开枪,直到叶子节点所以答案就为缩完点后入度为0的点。
我打完之后只过了一个点,因为这题有两个坑点,至少对我来说是这样的。
第一,指向这个点的点可以有好几个,但这个点的出度只有一个,虽然是废话,但在你判断谁存活的时候需要先判断一下,你目前队首的这个点所指向的点是否已经被杀掉,否则错炸了。
第二,也是卡住了无数英雄好汉的点,如何判断某个环是否已被用队列访问,开个bool记录看似容易,然而在哪里打标记就是大坑了,对于WA的童鞋们可以试一下这个点:
4
2 3 2 3
希望能帮到你们,在这个点中,环中每个人都死了,但如果你在将某个元素塞进队列时才将它打上标记你会发现实际已经访问了的环并未被打上标记,因此,正解是每个被塞进队列的人他所指向的人和他所指向的人所指向的人都要被打上标记。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 using namespace std; 9 int n,tt[1000004],st[1000005],top; 10 bool rz[1000005],rz2[1000005]; 11 int dfn[1000005],low[1000005],zz1; 12 int zz2,belong[1000005],sum[1000005]; 13 void tar(int x){ 14 zz1++; 15 top++; 16 st[top]=x; 17 rz[x]=rz2[x]=1; 18 dfn[x]=low[x]=zz1; 19 if(!rz2[tt[x]]) 20 { 21 tar(tt[x]); 22 low[x]=min(low[x],low[tt[x]]); 23 } 24 else if(rz[tt[x]]) 25 { 26 low[x]=min(low[x],dfn[tt[x]]); 27 } 28 if(dfn[x]==low[x]) 29 { 30 int v; 31 zz2++; 32 do{ 33 v=st[top]; 34 top--; 35 rz[v]=0; 36 sum[zz2]++; 37 belong[v]=zz2; 38 }while(dfn[v]!=low[v]); 39 } 40 } 41 int a[1000005],zz3,rd2[1000006],be[1000005]; 42 bool fw[1000005],js[1000005]; 43 int rd[1000005],ans1,ans2; 44 queue<int> q1; 45 int main(){ 46 scanf("%d",&n); 47 for(int i=1;i<=n;i++) 48 { 49 scanf("%d",&tt[i]); 50 rd[tt[i]]++; 51 } 52 for(int i=1;i<=n;i++) 53 if(!rz2[i]) 54 tar(i); 55 for(int i=1;i<=n;i++) 56 { 57 if(rd[i]==0) 58 { 59 ans1++; 60 q1.push(i); 61 fw[belong[i]]=1; 62 } 63 } 64 while(!q1.empty()) 65 { 66 int x=q1.front(); 67 q1.pop(); 68 fw[belong[tt[x]]]=1; 69 if(!js[tt[x]]) 70 { 71 js[tt[x]]=1; 72 rd[tt[tt[x]]]--; 73 if(rd[tt[tt[x]]]==0) 74 { 75 ans1++; 76 fw[belong[tt[tt[x]]]]=1; 77 q1.push(tt[tt[x]]); 78 } 79 } 80 } 81 for(int i=1;i<=zz2;i++) 82 { 83 if(!fw[i]) 84 { 85 ans1+=sum[i]/2; 86 } 87 } 88 for(int i=1;i<=n;i++) 89 { 90 if(belong[tt[i]]!=belong[i]||tt[i]==i) 91 { 92 rd2[belong[tt[i]]]++; 93 } 94 } 95 for(int i=1;i<=zz2;i++) 96 { 97 if(!rd2[i]) 98 ans2++; 99 } 100 printf("%d %d",n-ans1,n-ans2); 101 return 0; 102 } 103
对了,这道题打法不知一道,有兴趣的读者可以试一试别的方法,DP已被验证可行,贪心据说也可以,希望读者不要拘泥于一种打法。
标签:做了 printf 有一个 display bool 入队 poi2008 考试 scan
原文地址:http://www.cnblogs.com/liutianrui/p/7275916.html