杀人游戏
问题 p: 杀人游戏
时间限制: 1 Sec 内存限制: 128 MB提交: 14 解决: 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
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+5; struct node{ int to,nx; }p[maxn*3]; struct node2{ int to,nx; }q[maxn*3]; int n,m,dfn[maxn],low[maxn],head[maxn],tot,vis[maxn],scc[maxn],cnt,sz[maxn],d[maxn],head2[maxn]; double ans; void addedge(int s,int t){ p[++tot].to=t,p[tot].nx=head[s],head[s]=tot; } void addedge2(int s,int t){ d[t]++; q[++tot].to=t,q[tot].nx=head2[s],head2[s]=tot; } stack<int>sk; void tarjan(int cur){ dfn[cur]=low[cur]=++tot; sk.push(cur); vis[cur]=1; for(int i=head[cur];i;i=p[i].nx){ int to=p[i].to; if(!dfn[to]){ tarjan(to); low[cur]=min(low[cur],low[to]); } else if(!scc[to])low[cur]=min(low[cur],dfn[to]); } if(dfn[cur]==low[cur]){ int now; cnt++; do{ now=sk.top(); sk.pop(); vis[now]=0; scc[now]=cnt; sz[cnt]++; }while(now!=cur); } } int ok(int cur){ if(d[cur]||sz[cur]!=1)return 0; for(int i=head2[cur];i;i=q[i].nx){ if(d[q[i].to]==1)return 0; } return 1; } void rebuild(){ for(int i=1;i<=n;i++){ for(int j=head[i];j;j=p[j].nx){ if(scc[i]!=scc[p[j].to])addedge2(scc[i],scc[p[j].to]); } } } int main() { cin>>n>>m; for(int i=1;i<=m;i++){ int u,v; cin>>u>>v; addedge(u,v); } tot=0; for(int i=1;i<=n;i++){ if(!dfn[i])tarjan(i); } tot=0; rebuild(); for(int i=1;i<=cnt;i++){ if(!d[i])ans++; } for(int i=1;i<=cnt;i++){ if(ok(i)){ ans--; break; } } printf("%.6f",(double)(n-ans)/(double)n); return 0; }