tarjan+概率

                                                                                                                          杀人游戏

题目描述

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面查出谁是杀手。

警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。假如查证的对象是杀手,杀手将会把警察干掉。

现在警察掌握了每一个人认识谁。

每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。

问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

输入格式

第一行有两个整数 N,M。

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

输出格式

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

样例

样例输入1

5 4 
1 2 
1 3 
1 4 
1 5 

样例输出1

0.800000

样例输入2

4 2
1 2
2 3

样例输出2

0.750000

样例输入3

7 6
4 1
5 4
2 1
7 3
1 6
2 5

样例输出3

0.714286

数据范围与提示

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。

对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=100000+10,maxm=300000+10;
 5 struct Edge{
 6     int to,next,from;
 7 }e[maxm<<1];
 8 struct Node{
 9     int to,next;
10 }g[maxm<<1];
11 int head[maxn],tot=0;
12 void Insert(int a,int b){
13     e[++tot].to=b;
14     e[tot].from=a;
15     e[tot].next=head[a];
16     head[a]=tot;
17 }
18 int rhead[maxn],q=0;
19 void add(int a,int b){
20     g[++q].to=b;
21     g[q].next=rhead[a];
22     rhead[a]=q;
23 }
24 int dfn[maxn],low[maxn],clock=0,scc[maxn],sc=0,t=0,st[maxn],vis[maxn],size[maxn];
25 void tarjan(int u){
26     st[++t]=u;
27     vis[u]=1;
28     low[u]=dfn[u]=++clock;
29     for(int i=head[u];i;i=e[i].next){
30         int v=e[i].to;
31         if(!dfn[v]){
32             tarjan(v);
33             low[u]=min(low[u],low[v]);
34         }
35         else if(vis[v]){
36             low[u]=min(low[u],dfn[v]);
37         }
38     }
39     if(dfn[u]==low[u]){
40         sc++;
41         while(st[t]!=u){
42             size[sc]++;
43             scc[st[t]]=sc;
44             vis[st[t]]=0;
45             t--;
46         }
47         size[sc]++;
48         scc[st[t]]=sc;
49         vis[st[t]]=0;
50         t--;
51     }
52 }
53 int main(){
54     int n,m;
55     scanf("%d%d",&n,&m);
56     for(int i=1;i<=m;i++){
57         int x,y;
58         scanf("%d%d",&x,&y);
59         Insert(x,y);
60     }
61     for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
62     int flag=0;
63     int rd[maxn]={};
64     int out[maxn]={};
65     for(int i=1;i<=m;i++){
66         int u=e[i].from;
67         int v=e[i].to;
68         if(scc[u]!=scc[v]){
69             add(scc[u],scc[v]);
70             rd[scc[v]]++;
71             out[scc[u]]++;
72         }    
73     }
74     int ans=0;
75     for(int u=1;u<=sc;u++){
76         if(!rd[u]){
77             ans++;
78             if(size[u]==1){
79                 int cnt=0;
80                 for(int i=rhead[u];i;i=g[i].next){
81                     int v=g[i].to;
82                     if(rd[v]<=1) cnt=1;
83                 }
84                 if(cnt==0) flag=1;
85             }    
86         }
87     }
88     double a;
89     if(flag){
90         a=(double)(ans-1)/n;
91     }
92     else a=(double)ans/n;
93     printf("%.6lf\n",(double)1-a);
94     return 0;
95 }
View Code

 

posted @ 2020-07-17 20:34  ddoodd  阅读(117)  评论(0编辑  收藏  举报