1. 程式人生 > >殺人遊戲

殺人遊戲

保留小數 sam 結果 概率 num ems flag 通過 n)

問題 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 }

殺人遊戲