標籤:矛盾 一個人 san 接下來 選擇 ems 成功 直接 memset
2438: [中山市選2011]殺人遊戲
題目:傳送門
簡要題意:
給出n個點,m條有向邊,進行最少的訪問並且可以便利(n-1)個點,求這個方案成功的機率
題解:
一道非常好的題目!
題目要知道最大的存活機率,那麼也就是找到直接找到殺手的最小機率
那麼我們採用強聯通縮點:
統計每個聯通分量的入度,如果入度為0(證明除此聯通分量裡的點,沒有人可以知道連通分量裡的資訊,那就一定要先選一個人訪問),那麼sum++(因為依據題意,假如問到連通分量裡的任意一個人,只要ta不是殺手,那麼一定可以安全的遍曆強聯通分量裡的所有人)
接下來就是最關鍵的特判:
對於連通分量裡只有一個點的情況,如果它的入度為零,不一定就要訪問(這裡何前面似乎有些許矛盾)
解釋:如果有聯通分量只有一個家族成員,並且沒有入度,因為殺手只有一個,那麼我們完全可以在遍曆其他的n-1個點時得出答案(排除法嘛)
但是它的出度不一定為0,所以還要判斷一下在上面的基礎上,這個點連出去的邊是否能夠被其他點訪問(入度>1),很好理解吧
如果以上的都滿足,那麼sum--
還有一個小槽點:sum--一次就好了,因為如果有兩種相同的情況,那麼對於兩個獨立的點,我們還是要選擇一個訪問才能遍曆完成的
輸出1.0-double(sum)/double(n)
代碼:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 int n,m; 8 struct node 9 { 10 int x,y,next; 11 }a[1110000];int len,last[510000]; 12 void ins(int x,int y) 13 { 14 len++; 15 a[len].x=x;a[len].y=y; 16 a[len].next=last[x];last[x]=len; 17 } 18 struct edge 19 { 20 int x,y,next; 21 }e[1110000];int len1,last1[510000]; 22 void inss(int x,int y) 23 { 24 len1++; 25 e[len1].x=x;e[len1].y=y; 26 e[len1].next=last1[x];last1[x]=len1; 27 } 28 int cnt,tp,id; 29 int belong[510000],dfn[510000],low[510000],sta[510000],size[510000]; 30 bool v[510000]; 31 void dfs(int x) 32 { 33 low[x]=dfn[x]=++id; 34 sta[++tp]=x;v[x]=true; 35 for(int k=last[x];k;k=a[k].next) 36 { 37 int y=a[k].y; 38 if(dfn[y]==-1) 39 { 40 dfs(y); 41 low[x]=min(low[x],low[y]); 42 } 43 else 44 { 45 if(v[y]==true) 46 low[x]=min(low[x],dfn[y]); 47 } 48 } 49 if(low[x]==dfn[x]) 50 { 51 int i;cnt++; 52 do{ 53 i=sta[tp--]; 54 v[i]=false; 55 belong[i]=cnt; 56 size[cnt]++; 57 }while(i!=x); 58 } 59 } 60 int ru[510000],chu[510000],sum1,sum2; 61 bool check(int x) 62 { 63 if(size[x]!=1)return true; 64 if(last1[x]==0)return false; 65 for(int k=last1[x];k;k=e[k].next) 66 { 67 int y=e[k].y; 68 if(ru[y]<=1)return true; 69 } 70 return false; 71 } 72 int main() 73 { 74 cnt=tp=id=sum1=sum2=0; 75 len=0;len1=0; 76 memset(last,0,sizeof(last));memset(last1,0,sizeof(last1)); 77 scanf("%d%d",&n,&m); 78 memset(chu,0,sizeof(chu)); 79 memset(ru,0,sizeof(ru)); 80 memset(sta,0,sizeof(sta)); 81 memset(dfn,-1,sizeof(dfn)); 82 memset(low,0,sizeof(low)); 83 memset(v,false,sizeof(v)); 84 for(int i=1;i<=m;i++) 85 { 86 int x,y; 87 scanf("%d%d",&x,&y); 88 ins(x,y); 89 } 90 for(int i=1;i<=n;i++) 91 if(dfn[i]==-1) 92 dfs(i); 93 for(int i=1;i<=m;i++) 94 { 95 int st=belong[a[i].x],ed=belong[a[i].y]; 96 if(st!=ed) 97 { 98 ru[ed]++; 99 inss(st,ed);100 }101 }102 for(int i=1;i<=cnt;i++)103 if(ru[i]==0)sum1++;104 for(int i=1;i<=cnt;i++)105 if(ru[i]==0)106 if(check(i)==false){sum1--;break;}107 printf("%.6lf\n",1.0-double(sum1)/double(n));108 return 0;109 }
bzoj2438: [中山市選2011]殺人遊戲(強聯通+特判)