首页 > 代码库 > [补档][中山市选2011]杀人游戏
[补档][中山市选2011]杀人游戏
题目
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人,谁是杀手,谁是平民。假如查证的对象是杀手,杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?INPUT
第一行有两个整数 N,M。接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x)。OUTPUT
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。SAMPLE
INPUT
5 41 21 31 41 5OUTPUT
0.800000
解题报告
考试时没想出来,随便打的输出样例- -
正解:
警察只有两种结果——查到犯人或者死,而死一定是包含在“调查未知身份的人”,也就是说调查未知身份的人越多,死亡概率越高,所以我们要求警察如何尽可能少调查未知身份的人
那么问题就很简单了,我们发现对于一个强连通分量,我们可以把他们看作一个人,因为调查了其中一个,剩余的都可以安全到达(正确性显然,因为你只要安全调查了其中的一个人,你就可以通过每次确认安全的人从而调查整个强连通分量),那么我们就可以tarjan一下,那么我们调查的对象就为缩点后入度为0的点(因为你无法从其他点通向这个点,你只能通过调查其中一个未知身份的人来调查整个强连通分量,如果警察RP不好,第一个选中杀手,警察就GG了),所以调查的未知身份的人数就是这些点的数量。
坑点:
存在这样一种情况,至少有一个点,且只有一个人,而且没人认识他,他也不认识别人,或者他认识的每个人都能被除他以外的其他人所认识(即入度>1),那么我们调查完其他人后,他就是杀手(正确性显然,对于第一种情况,考虑n=1就行,对于第二种情况,他认识的人已经被调查过了,而其他人自然也被调查过,那么他自己就是剩下未调查的唯一可能的杀手)。
那么如何处理呢?
进行特判,顺便dfs一下,判断是否属于这种情况就可以啦
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6 int sum(0); 7 char ch(getchar()); 8 for(;ch<‘0‘||ch>‘9‘;ch=getchar()); 9 for(;ch>=‘0‘&&ch<=‘9‘;sum=sum*10+(ch^48),ch=getchar()); 10 return sum; 11 } 12 struct edge{ 13 int s,e,n; 14 }a[300001],b[100001]; 15 int pre[100001],tot; 16 int adj[100001],ttt; 17 inline void insert(int s,int e){ 18 a[++tot].s=s; 19 a[tot].e=e; 20 a[tot].n=pre[s]; 21 pre[s]=tot; 22 } 23 inline void add(int s,int e){ 24 b[++ttt].s=s; 25 b[ttt].e=e; 26 b[ttt].n=adj[s]; 27 adj[s]=ttt; 28 } 29 int n,m; 30 int stack[100001],top; 31 int cnt,low[100001],dfn[100001],bl[100001],qlt; 32 bool vis[100001]; 33 int size[100001]; 34 inline int my_min(int a,int b){ 35 return a<b?a:b; 36 } 37 inline void tarjan(int u){ 38 cnt++; 39 vis[u]=1; 40 low[u]=dfn[u]=cnt; 41 stack[++top]=u; 42 for(int i=pre[u];i!=-1;i=a[i].n){ 43 int e(a[i].e); 44 if(!dfn[e]){ 45 tarjan(e); 46 low[u]=my_min(low[u],low[e]); 47 } 48 else 49 if(vis[e]) 50 low[u]=my_min(low[u],dfn[e]); 51 } 52 if(low[u]==dfn[u]){ 53 int tmp; 54 qlt++; 55 while(1){ 56 tmp=stack[top--]; 57 bl[tmp]=qlt; 58 vis[tmp]=0; 59 if(tmp==u) 60 break; 61 } 62 } 63 } 64 bool flag[100001]; 65 inline void uni(int u){//坑点处理dfs 66 for(int i=adj[u];i!=-1;i=b[i].n){ 67 int e(b[i].e); 68 if(!vis[e]){ 69 vis[e]=1; 70 uni(e); 71 size[u]+=size[e]; 72 } 73 } 74 } 75 int ans(0); 76 int ind[100001]; 77 int main(){ 78 // freopen("killer.in","r",stdin); 79 // freopen("killer.out","w",stdout); 80 memset(pre,-1,sizeof(pre)); 81 memset(adj,-1,sizeof(adj)); 82 n=read(),m=read(); 83 for(int i=1;i<=m;i++){ 84 int x(read()),y(read()); 85 insert(x,y); 86 } 87 for(int i=1;i<=n;i++) 88 if(!dfn[i]) 89 tarjan(i); 90 for(int i=1;i<=n;i++) 91 size[bl[i]]++; 92 for(int i=1;i<=m;i++){ 93 int s(a[i].s),e(a[i].e); 94 if(bl[s]!=bl[e]) 95 add(bl[s],bl[e]),ind[bl[e]]++; 96 } 97 for(int i=1;i<=qlt;i++) 98 if(!ind[i]){//坑点特判 99 uni(i); 100 if(size[i]==1){ 101 ans=-1; 102 break; 103 } 104 } 105 for(int i=1;i<=qlt;i++) 106 if(ind[i]==0) 107 ans++; 108 printf("%.6lf",(double)(n-ans)/(double)n); 109 }
哀民生之多艰啊- -
[补档][中山市选2011]杀人游戏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。