bzoj2438: [中山市选2011]杀人游戏(强联通+特判)
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 }