杀人游戏
问题 p: 杀人游戏
时间限制: 1 Sec 内存限制: 128 MB提交: 3 解决: 2
[提交] [状态] [讨论版] [命题人:admin]
题目描述
一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?
输入
第一行有两个整数 N,M。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。
输出
仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。
样例输入
5 4
1 2
1 3
1 4
1 5
样例输出
0.800000
提示
警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000
Tarjan缩点后求强连通,有x个入度为0的点,则需要调查x次,则最后安全几率为1-x/n。
但这样不完全对,存在一种情况,当警察调查完x-1个人之后,他可以直接确定最后一个人是不是罪犯。这样安全的几率为1-(x-1)/n。而其充分条件为该入度为0的强连通分量,其相连的其他强连通分量入度大于1,。
#include <bits/stdc++.h>
#define maxn 200000
using namespace std;
int ind[maxn],low[maxn],dfn[maxn],in[maxn],out[maxn],tot,cnt;
bool vis[maxn];
vector<int> a[maxn];
stack<int> s;
struct Edge
{
int v,next;
};
struct M
{
int head[maxn];
Edge edge[maxn*3];
int cnt;
void init()
{
memset(head,-1, sizeof(head));
cnt=0;
}
void addedge(int u,int v)
{
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
}Mp;
void Tarjan(int num)
{
vis[num]=true;
low[num]=dfn[num]=++tot;
s.push(num);
for(int i=Mp.head[num];i!=-1;i=Mp.edge[i].next)
{
int v=Mp.edge[i].v;
if(!dfn[v])
{ Tarjan(v);
low[num]=min(low[num],low[v]);
}
else if(vis[v])
{
low[num]=min(low[num],dfn[v]);
}
}
if(dfn[num]==low[num])
{ ++cnt;
while(true)
{
int now=s.top();
a[cnt].push_back(now);
s.pop();
vis[now]=false;
ind[now]=cnt;
if(now==num) break;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m,u,v;
scanf("%d%d",&n,&m);
Mp.init();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
Mp.addedge(u,v);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i]) Tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=Mp.head[i];j!=-1;j=Mp.edge[j].next)
{
int v=Mp.edge[j].v;
if(ind[v]!=ind[i])
{
in[ind[v]]++;
out[ind[i]]++;
}
}
}
int sum=0;
for(int i=1;i<=cnt;i++)
{
if(in[i]==0) sum++;
}
double ans;
for(int i=1;i<=cnt;i++)
{
if(in[i]==0&&a[i].size()==1)
{
int u=a[i][0];
bool f=false;
for(int j=Mp.head[u];j!=-1;j=Mp.edge[j].next)
{
int v=Mp.edge[j].v;
if(in[ind[v]]<=1) f=true;
}
if(f==false)
{
sum--;
break;
}
}
}
ans=1-1.0*sum/n;
printf("%.6lf\n",ans);
}

浙公网安备 33010602011771号