bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)相关的知识,希望对你有一定的参考价值。
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2438
【题意】
N个人中有一个杀手,每次询问一个人可能被杀或被告知其认识的人中谁是杀手谁是平民,问不被杀的情况下知道谁是杀手的概率。
【思路】
对于一个scc,如果我们询问一个不是杀手的人,就可以成功遍历整个scc。
求scc,然后缩点。
对于每一个入度为0的scc,我们需要去询问一下,那么被杀的概率为1/n * ans。ans为入度为0的scc个数。
但还有一种特殊的情况,如果一个scc入度为0,但它的所有出度的入度皆大于1,那么它的出度可以不通过询问这个scc得知,而且最终通过其他n-1个点推出这个点的情况。这时候需要对ans-1,但这种情况只计算一次。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 2e5+10; 15 const int M = 7e5+10; 16 17 ll read() { 18 char c=getchar(); 19 ll f=1,x=0; 20 while(!isdigit(c)) { 21 if(c==‘-‘) f=-1; c=getchar(); 22 } 23 while(isdigit(c)) 24 x=x*10+c-‘0‘,c=getchar(); 25 return x*f; 26 } 27 28 struct Edge { 29 int v,nxt; 30 }e[M]; 31 int en=1,front[N]; 32 void adde(int u,int v) 33 { 34 e[++en]=(Edge){v,front[u]}; front[u]=en; 35 } 36 37 int pre[N],lowlink[N],scc_cnt,sccno[N],S[N],top,dfn; 38 39 void tarjan(int u) 40 { 41 pre[u]=lowlink[u]=++dfn; 42 S[++top]=u; 43 trav(u,i) { 44 int v=e[i].v; 45 if(!pre[v]) { 46 tarjan(v); 47 lowlink[u]=min(lowlink[v],lowlink[u]); 48 } else 49 if(!sccno[v]) 50 lowlink[u]=min(lowlink[u],pre[v]); 51 } 52 if(pre[u]==lowlink[u]) { 53 ++scc_cnt; 54 for(;;) { 55 int x=S[top--]; 56 sccno[x]=scc_cnt; 57 if(x==u) break; 58 } 59 } 60 } 61 62 int cnt[N],in[N],n,m,ans; 63 64 int main() 65 { 66 n=read(),m=read(); 67 int u,v; 68 FOR(i,1,m) { 69 u=read(),v=read(); 70 adde(u,v); 71 } 72 FOR(i,1,n) if(!pre[i]) tarjan(i); 73 FOR(u,1,n) { 74 cnt[sccno[u]]++; 75 trav(u,i) { 76 int v=e[i].v; 77 if(sccno[u]!=sccno[v]) 78 in[sccno[v]]++; 79 } 80 } 81 FOR(i,1,scc_cnt) if(!in[i]) ans++; 82 int flag=0; 83 FOR(i,1,n) 84 if(cnt[sccno[i]]==1&&in[sccno[i]]==0) { 85 int f=1; 86 trav(i,j) { 87 int v=e[j].v; 88 if(in[sccno[v]]<=1) { f=0; break; } 89 } 90 if(f) { 91 flag=1; break; 92 } 93 } 94 ans-=flag; 95 printf("%.6lf\n",(double)(n-ans)/n); 96 return 0; 97 }
以上是关于bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj2438: [中山市选2011]杀人游戏(强联通+特判)