1. 程式人生 > >[中山市選2011]殺人遊戲

[中山市選2011]殺人遊戲

size ask 小數點 輸入 ems href space tarjan縮點 sta

[中山市選2011]殺人遊戲

時間限制: 1 Sec 內存限制: 128 MB
提交: 64 解決: 33
[提交][狀態][討論版]

題目描述

一位冷血的殺手潛入 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的點中,這些人是殺手的概率就是死亡的概率,但是要註意的是,如果一個人不被任何人認識且不認識任何人,那麽當排除其他所有人後,他一定是殺手,所以要把他減掉,還有的就是如果一個人不被其他任何人認識,且他認識的人都被其他人認識,那麽在排除其他人後,也能確定他是不是殺手,也應被減掉

[中山市選2011]殺人遊戲