[bzoj 2438][中山市选2011]杀人游戏 概率+tarjan

来源:互联网 发布:什么叫品牌战略 知乎 编辑:程序博客网 时间:2024/05/21 22:31

考试的时候想了很多,不知道它那个概率究竟是怎么算。。没想到能蒙30分。rp爆发hhh

题解转自不知道哪里来的老师发的(代码出自自己)。

实际上警察就是两种结果——查到犯人或死亡,而死亡事件一定是包含在“调查未知身份的人”,也就是说调查未知身份的人越多,死亡概率就越高,所以我们要求的问题就是警察要尽可能少调查未知身份的人 
给出公式 P(死亡)=调查的未知身份的人数/总人数 

“死亡”和”存活”是对立事件,而”存活”等价于”找到犯人” 所以 ans=1−P死亡 问题转化为求调查最少的未知身份人的人数 
同时我们发现,对于一个环(1认识2,2认识3,3认识1),我们是可以把他们看作一个人的,也就是说,只要调查了他们其中一个,其他两个我们一定可以安全到达(知道他是犯人或平民) 对于这个问题,我们使用tarjan对图进行缩点处理,然后我们所要调查的对象就是重构图中那些入度为0的点(没有人知道这些点里的人的身份),调查的未知身份的人数就是这些点的数量 (如果其中入度不为0,那么我们一定可以从一个入度为0的点走到这里,即我们调查这个点时是知道这里面的人的身份的) 
注意: 
有一个特殊情况,如果说至少有一个点,它只有一个人,他是完全孤立的(即没有人知道这个人的身份,他对外面的世界也一无所知)或者他认识的每个人都被除他以外的其他人所认识(即它所能到达的点的入度>1),那么我们在安全调查完除他以外的其他人后,他一定是杀手(但在图上他属于未知身份的人),我们不必去调查他,直接抓起来就可以了,所以调查未知身份的人数要– 1(我们可以想得简单些,比如n=1时这个人一定是杀手,即P存活=1) 

#include<cstdio>#include<cstring>#include<iostream>using namespace std;#define pos(i,a,b) for(int i=(a);i<=(b);i++)#define N 500000int n,m;int low[N],dfn[N],stack[N],instack[N],belong[N];int peo[N];struct haha{int next,to;};haha edgechu[N],edge[N];int head[N],cnt=1,cntchu=1,headchu[N];void add(int u,int v){edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt++;}void addchu(int u,int v){edgechu[cntchu].to=v;edgechu[cntchu].next=headchu[u];headchu[u]=cntchu++;}int ji=1,hea,cn=1;void tarjan(int now){low[now]=dfn[now]=ji++;stack[++hea]=now;instack[now]=1;for(int i=headchu[now];i;i=edgechu[i].next){int to=edgechu[i].to;if(dfn[to]==-1){tarjan(to);low[now]=min(low[now],low[to]);}else{if(instack[to]){low[now]=min(low[now],dfn[to]);}}}if(low[now]==dfn[now]){int temp;while(1){temp=stack[hea--];belong[temp]=cn;instack[temp]=0;peo[cn]++;if(temp==now)  break;}cn++;}}int in[N],out[N];int ans;int flag[N];int main(){freopen("killer.in","r",stdin);freopen("killer.out","w",stdout);scanf("%d%d",&n,&m);memset(dfn,-1,sizeof(dfn));pos(i,1,m){int x,y;scanf("%d%d",&x,&y);addchu(x,y);}pos(i,1,n){   if(dfn[i]==-1)tarjan(i);}cn--;pos(i,1,n){for(int v=headchu[i];v;v=edgechu[v].next){int j=edgechu[v].to;if(belong[i]!=belong[j]){add(belong[i],belong[j]);in[belong[j]]++;out[belong[i]]++;}}}pos(i,1,cn){if(in[i]==0){ans++;}}pos(i,1,cn){if(peo[i]==1){if(in[i]==0&&out[i]==0){ans--;double temp=(double)(n-ans)/n;printf("%0.6lf",temp);return 0;}else{for(int j=head[i];j;j=edge[j].next){int to=edge[j].to;if(in[to]>1){flag[i]++; }}if(flag[i]==out[i]&&(flag[i])){ans--;double temp=(double)(n-ans)/n;printf("%0.6lf",temp);return 0;} }}}double temp=(double)(n-ans)/n;printf("%0.6lf",temp);return 0;}


阅读全文
2 0
原创粉丝点击