[中山市选2011]杀人游戏
[中山市选2011]杀人游戏
时间限制: 1 Sec 内存限制: 128 MB题目描述
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,
查出谁是杀手。
警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他
认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。
现在警察掌握了每一个人认识谁。
每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。
问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多
少?
输入
第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,
1 #include<cmath> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 # define maxn 100010 8 using namespace std; 9 struct node{ 10 int u,v,nxt; 11 }g[310000]; 12 int adj[310000],e; 13 void add(int u,int v){ 14 g[++e].v=v; g[e].u=u; 15 g[e].nxt=adj[u]; adj[u]=e; 16 } 17 int n,m; 18 int stack[maxn],dfn[maxn],low[maxn],belong[maxn],cnt,step,head; 19 bool instack[maxn]; 20 void tarjan(int x){ 21 dfn[x]=low[x]=++step; 22 instack[x]=1; 23 stack[++head]=x; 24 for(int i=adj[x];i;i=g[i].nxt){ 25 int v=g[i].v; 26 if(dfn[v]==-1){ 27 tarjan(v); 28 low[x]=min(low[x],low[v]); 29 } 30 else if(instack[v]){ 31 low[x]=min(low[x],dfn[v]); 32 } 33 } 34 if(dfn[x]==low[x]){ 35 int temp; 36 cnt++; 37 while(1){ 38 temp=stack[head--]; 39 instack[temp]=0; 40 belong[temp]=cnt; 41 if(x==temp) break; 42 } 43 } 44 } 45 int ru[maxn]; 46 int chu[maxn],to[maxn]; 47 int main(){ 48 // freopen("a.in","r",stdin); 49 //freopen("killer.in","r",stdin); freopen("killer.out","w",stdout); 50 scanf("%d%d",&n,&m); 51 int x,y; 52 for(int i=1;i<=m;i++){ 53 scanf("%d%d",&x,&y); 54 add(x,y); 55 chu[x]++; to[y]++; 56 } 57 memset(dfn,-1,sizeof(dfn)); 58 for(int i=1;i<=n;i++){ 59 if(dfn[i]==-1){ 60 tarjan(i); 61 } 62 } 63 bool flag=0; 64 int ji=0; 65 for(int i=1;i<=n;i++){ 66 if(chu[i]==0 && to[i]==0){ 67 flag=1; 68 } 69 int v; 70 bool rp=1; 71 for(int j=adj[i];j;j=g[j].nxt){ 72 v=g[j].v; 73 if(to[v]<=1) rp=0; 74 if(belong[v]!=belong[i]) 75 ru[belong[v]]++; 76 } 77 if(to[i]==0 && rp) flag=1; 78 } 79 for(int i=1;i<=cnt;i++){ 80 if(ru[i]==0){ 81 ji++; 82 } 83 } 84 //cout<<"n== "<<n<<" "<<ji<<" "<<cnt<<" "<<flag<<endl; 85 if(flag) ji--; 86 double ans=(1.0-(double)ji/n); 87 printf("%.6lf",ans); 88 return 0; 89 90 }
) 。
输出
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。
样例输入
5 4
1 2
1 3
1 4
1 5
样例输出
0.800000
这道题开始的分析很关键,首先如果去问一个人,如果这个人不是杀手,那么以他为根的一棵树中所有人的身份都可以知道,所以剩下的人就不存在被杀的风向,所以先用tarjan缩点,将所有的环缩掉这样就可以把一个环当成一个人,之后再这个DAG中,寻找所有入度为0的点,这些点无法通过其他点来排除,所以这个点必须询问,所以在找到的这几个入为0的点中,这些人是杀手的概率就是死亡的概率,但是要注意的是,如果一个人不被任何人认识且不认识任何人,那么当排除其他所有人后,他一定是杀手,所以要把他减掉,还有的就是如果一个人不被其他任何人认识,且他认识的人都被其他人认识,那么在排除其他人后,也能确定他是不是杀手,也应被减掉