您的位置:首页 > 其它

[bzoj2438][中山市选2011]杀人游戏

2017-05-25 20:33 337 查看
来自FallDream的博客,未经允许,请勿转载,谢谢。

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。

警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。

现在警察掌握了每一个人认识谁。 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。

问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

n<=100000 m<=300000

tarjan缩点之后,推一波公式,发现只要查的是入度为0的点,顺序并没有影响。

要特殊处理的是大小为1的点。当然一个联通块也有可能在查了一个人之后剩下的部分大小是1。我们可以把入度为0的点按照大小排序之后从大到小dfs,就可以找到这种情况。

答案是(n-入度为0的点的个数+是否有大小为1的点)/n

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MN 200000
using namespace std;
inline int read()
{
int x = 0 , f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}

bool mark[MN+5],inq[MN+5];
int cnt=0,dn=0,cc,in[MN+5],sum=0,head[MN+5],size[MN+5],q[MN+5],top=0,bel[MN+5],n,m,dfn[MN+5],low[MN+5];
struct edge{int to,next;}e[MN*3+5];

inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}

void tarjan(int x)
{
dfn[x]=low[x]=++dn;q[++top]=x;inq[x]=1;
for(int i=head[x];i;i=e[i].next)
if(!dfn[e[i].to]) tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);
else if(inq[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
if(dfn[x]==low[x])
for(++cc;q[top+1]!=x;bel[q[top]]=cc,inq[q[top]]=0,++size[cc],--top);
}
bool cmp(int x,int y){return size[x]>size[y];}

void Dfs(int x)
{
sum+=size[x];mark[x]=1;
for(int i=head[x];i;i=e[i].next)
if(!mark[e[i].to]) Dfs(e[i].to);
}

int main()
{
cc=n=read();m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
ins(x,y);
}
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;++i)
for(int j=head[i];j;j=e[j].next)
if(bel[i]!=bel[e[j].to])
ins(bel[i],bel[e[j].to]),++in[bel[e[j].to]];
for(int i=n+1;i<=cc;++i) if(!in[i]) q[++top]=i;
sort(q+1,q+top+1,cmp);
int ans=n-top;
for(int i=1;i<=top;++i)
{
sum=0;Dfs(q[i]);
if(sum==1) {++ans;break;}
}
printf("%.6lf",(double)ans/n);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: