给出一个有向图,然后问你每次可以查证一个人,而这个人可能是平民,如果是平民他会告诉你所有他认识的人是什么身份。如果是杀手,你就被杀手杀了。只有一个杀手而且每个人是杀手的概率是等同的。问你在保证安全的情况下知道谁是杀手的最大概率。
事实上,假设你选择了
k
k
k个人,你被杀的概率为
k
n
\frac{k}{n}
nk。因此你要选择最少人,假设一堆人在一个强连通分量里面那么你只要查证其中任意一个人。而缩点之后我们想要知道所有人,只需要所有的入度为0的点即可。
所以
k
k
k取入度为
0
0
0的环的个数。然后特判一种情形,就是假设存在某一个入度为0的环,它只有其中一个点并且它出边到达的点都可以被其它点到达。这个点可以不需要查证。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e5+7;
vector<int> G[N];
int n,m;
int dfn[N],low[N],bel[N],s[N],in[N],sz[N],top=0;
int tim=0,scc=0;
bool ins[N];
void tarjan(int u) {
dfn[u]=low[u]=++tim;
s[++top]=u;
ins[u]=1;
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(ins[v]) {
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]) {
bel[u]=++scc;
ins[u]=0;
sz[scc]++;
while(s[top]!=u) {
bel[s[top]]=scc;
ins[s[top]]=0;
sz[scc]++;
top--;
}
top--;
}
}
void solve() {
for(int i=1;i<=n;i++) {
if(!dfn[i]) {
tarjan(i);
}
}
for(int i=1;i<=n;i++) {
for(int j=0;j<G[i].size();j++) {
int u=bel[i];
int v=bel[G[i][j]];
if(u==v) continue;
in[v]++;
}
}
}
bool check(int u) {
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(bel[u]==bel[v]) continue;
if(in[bel[v]]==1) return 0;
}
return 1;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
}
solve();
int cnt=0;
for(int i=1;i<=scc;i++) {
if(!in[i]) ++cnt;
}
for(int i=1;i<=n;i++) {
if(!in[bel[i]]&&sz[bel[i]]==1&&check(i)) {
--cnt;
break;
}
}
printf("%.6lf\n",(double)(n-cnt)/n);
return 0;
}