1. 程式人生 > 實用技巧 >tarjan+概率

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