首页 > 技术文章 > 杀人游戏

Maplers 2017-07-29 06:20 原文

问题 C: [中山市选2011]杀人游戏

题目描述

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,
查出谁是杀手。 
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他
认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。 
现在警察掌握了每一个人认识谁。 
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。 
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多
少?

输入

第一行有两个整数 N,M。 
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。

输出

仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。

样例输入

5 4 
1 2 
1 3 
1 4 
1 5 

样例输出

0.800000 

 

 

杀人游戏:

比较难的是怎么想出来如何计算概率:

  警察在搜寻的过程中只有两种结果——找到犯人或死亡,而死亡意味着你找的人是罪犯,因为每个人是罪犯的概率是相等的,所以问题转化为了要调查尽可能少的人来确定所有人的身份,注意到这是一个有向图,所以对那些强连通分量进行tarjan缩点处理,因为只要调查了他们中的一个人,那么就能知道其中所有人的身份,缩点完后在新建的图中是一个森林,我们要找的是那些入度为0的点,结果就是点的数量/总点数,入度不为0那一定能通过其他的点到达这里;

  注意到会有一种特殊情况:如果有一个点没有入度也没有出度(初始时),那么只要调查了其他所有人都不是罪犯,则警察可以不用再去调查他了,他一定罪犯,所以在新图中进行判断,如果入度出度均为0且缩点后点的大小为0且其所能到达的点中只有一个初度,就对点的数量-1/sum就是结果了。

 代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 vector<int>v[100001];
 8 int n,m,x,y,num,cnt,dex;
 9 int adj[100001],in[100001],out[100001];
10 int dfn[100001],low[100001],belong[100001];
11 struct edge{
12     int s,t,next;
13 }k[300001],a[300001];
14 int read(){
15     int sum=0;char ch=getchar();
16     while(ch<'0'||ch>'9') ch=getchar();
17     while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
18     return sum;
19 }
20 void init(int x,int y){
21     k[num].s=x;k[num].t=y;
22     k[num].next=adj[x];adj[x]=num++;
23 }
24 bool t[100001];int zhan[100001],size[100001],head;
25 void tarjan(int x){
26     dfn[x]=low[x]=++dex;
27     t[x]=1;zhan[++head]=x;
28     for(int i=adj[x];i!=-1;i=k[i].next){
29         int o=k[i].t;
30         if(dfn[o]==-1){
31             tarjan(o);
32             low[x]=min(low[x],low[o]);
33         }
34         else
35             if(t[o])
36                 low[x]=min(low[x],dfn[o]);      
37     }
38     if(low[x]==dfn[x]){
39         int temp;cnt++;
40         while(1){
41             temp=zhan[head--];
42             belong[temp]=cnt;
43             t[temp]=0;size[cnt]++;
44             if(temp==x)
45                 break;
46         }
47     }   
48 }
49 bool search(int x){
50     for(int i=0;i<v[x].size();++i)
51         if(in[v[x][i]]==1)
52             return false;
53     return true;
54 }
55 int main(){
56 //  freopen("killer.in","r",stdin);
57 //  freopen("killer.out","w",stdout);
58     memset(adj,-1,sizeof(adj));
59     memset(dfn,-1,sizeof(dfn));
60     n=read();m=read();
61     for(int i=1;i<=m;++i){
62         x=read();y=read();
63         init(x,y);
64     }
65     for(int i=1;i<=n;++i)
66         if(dfn[i]==-1)
67             tarjan(i);
68     for(int i=0;i<num;++i){
69         if(belong[k[i].t]!=belong[k[i].s]){
70             in[belong[k[i].t]]++;
71             out[belong[k[i].s]]++;
72             v[belong[k[i].s]].push_back(belong[k[i].t]);
73         }
74     }
75     int ans=0;bool flag=false;
76     for(int i=1;i<=cnt;++i){
77         if(!in[i])
78             ans++;
79         if((!in[i]&&!out[i]&&size[i]==1)||(!flag&&!in[i]&&search(i)&&size[i]==1))
80             flag=true;
81     }
82     if(flag) ans--;
83     double res=1-(double)ans/n;
84     printf("%.6lf",res);
85      //while(1);
86     return 0;
87 }

 

推荐阅读