[中山市选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的点中,这些人是杀手的概率就是死亡的概率,但是要注意的是,如果一个人不被任何人认识且不认识任何人,那么当排除其他所有人后,他一定是杀手,所以要把他减掉,还有的就是如果一个人不被其他任何人认识,且他认识的人都被其他人认识,那么在排除其他人后,也能确定他是不是杀手,也应被减掉
posted @ 2017-07-29 21:34  Nawox  阅读(299)  评论(0编辑  收藏  举报