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

[補檔][中山市選2011]殺人遊戲

表示 -- opened center 有一個 style splay set color

題目

一位冷血的殺手潛入 Na-wiat,並假裝成平民。警察希望能在 N 個人裏面,查出誰是殺手。 警察能夠對每一個人進行查證,假如查證的對象是平民,他會告訴警察,他認識的人,誰是殺手,誰是平民。假如查證的對象是殺手,殺手將會把警察幹掉。 現在警察掌握了每一個人認識誰。 每一個人都有可能是殺手,可看作他們是殺手的概率是相同的。 問:根據最優的情況,保證警察自身安全並知道誰是殺手的概率最大是多少?

INPUT

第一行有兩個整數 N,M。 接下來有 M 行,每行兩個整數 x,y,表示 x 認識 y(y 不一定認識 x)。

OUTPUT

僅包含一行一個實數,保留小數點後面 6 位,表示最大概率。

SAMPLE

INPUT

5 4 1 2 1 3 1 4 1 5

OUTPUT

0.800000

解題報告

考試時沒想出來,隨便打的輸出樣例- - 正解: 警察只有兩種結果——查到犯人或者死,而死一定是包含在“調查未知身份的人”,也就是說調查未知身份的人越多,死亡概率越高,所以我們要求警察如何盡可能少調查未知身份的人 那麽問題就很簡單了,我們發現對於一個強連通分量,我們可以把他們看作一個人,因為調查了其中一個,剩余的都可以安全到達(正確性顯然,因為你只要安全調查了其中的一個人,你就可以通過每次確認安全的人從而調查整個強連通分量),那麽我們就可以tarjan一下,那麽我們調查的對象就為縮點後入度為0的點(因為你無法從其他點通向這個點,你只能通過調查其中一個未知身份的人來調查整個強連通分量,如果警察RP不好,第一個選中殺手,警察就GG了),所以調查的未知身份的人數就是這些點的數量。 坑點: 存在這樣一種情況,至少有一個點,且只有一個人,而且沒人認識他,他也不認識別人,或者他認識的每個人都能被除他以外的其他人所認識(即入度>1),那麽我們調查完其他人後,他就是殺手(正確性顯然,對於第一種情況,考慮n=1就行,對於第二種情況,他認識的人已經被調查過了,而其他人自然也被調查過,那麽他自己就是剩下未調查的唯一可能的殺手)。 那麽如何處理呢? 進行特判,順便dfs一下,判斷是否屬於這種情況就可以啦 技術分享
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 inline int read(){
  6     int sum(0);
  7     char ch(getchar());
  8     for(;ch<0||ch>9;ch=getchar());
  9     for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar());
10 return sum; 11 } 12 struct edge{ 13 int s,e,n; 14 }a[300001],b[100001]; 15 int pre[100001],tot; 16 int adj[100001],ttt; 17 inline void insert(int s,int e){ 18 a[++tot].s=s; 19 a[tot].e=e; 20 a[tot].n=pre[s]; 21 pre[s]=tot; 22 } 23 inline void add(int s,int e){ 24 b[++ttt].s=s; 25 b[ttt].e=e; 26 b[ttt].n=adj[s]; 27 adj[s]=ttt; 28 } 29 int n,m; 30 int stack[100001],top; 31 int cnt,low[100001],dfn[100001],bl[100001],qlt; 32 bool vis[100001]; 33 int size[100001]; 34 inline int my_min(int a,int b){ 35 return a<b?a:b; 36 } 37 inline void tarjan(int u){ 38 cnt++; 39 vis[u]=1; 40 low[u]=dfn[u]=cnt; 41 stack[++top]=u; 42 for(int i=pre[u];i!=-1;i=a[i].n){ 43 int e(a[i].e); 44 if(!dfn[e]){ 45 tarjan(e); 46 low[u]=my_min(low[u],low[e]); 47 } 48 else 49 if(vis[e]) 50 low[u]=my_min(low[u],dfn[e]); 51 } 52 if(low[u]==dfn[u]){ 53 int tmp; 54 qlt++; 55 while(1){ 56 tmp=stack[top--]; 57 bl[tmp]=qlt; 58 vis[tmp]=0; 59 if(tmp==u) 60 break; 61 } 62 } 63 } 64 bool flag[100001]; 65 inline void uni(int u){//坑點處理dfs 66 for(int i=adj[u];i!=-1;i=b[i].n){ 67 int e(b[i].e); 68 if(!vis[e]){ 69 vis[e]=1; 70 uni(e); 71 size[u]+=size[e]; 72 } 73 } 74 } 75 int ans(0); 76 int ind[100001]; 77 int main(){ 78 // freopen("killer.in","r",stdin); 79 // freopen("killer.out","w",stdout); 80 memset(pre,-1,sizeof(pre)); 81 memset(adj,-1,sizeof(adj)); 82 n=read(),m=read(); 83 for(int i=1;i<=m;i++){ 84 int x(read()),y(read()); 85 insert(x,y); 86 } 87 for(int i=1;i<=n;i++) 88 if(!dfn[i]) 89 tarjan(i); 90 for(int i=1;i<=n;i++) 91 size[bl[i]]++; 92 for(int i=1;i<=m;i++){ 93 int s(a[i].s),e(a[i].e); 94 if(bl[s]!=bl[e]) 95 add(bl[s],bl[e]),ind[bl[e]]++; 96 } 97 for(int i=1;i<=qlt;i++) 98 if(!ind[i]){//坑點特判 99 uni(i); 100 if(size[i]==1){ 101 ans=-1; 102 break; 103 } 104 } 105 for(int i=1;i<=qlt;i++) 106 if(ind[i]==0) 107 ans++; 108 printf("%.6lf",(double)(n-ans)/(double)n); 109 }
View Code 哀民生之多艱啊- -

[補檔][中山市選2011]殺人遊戲