分析
缩点后显然只考虑入度为0的点的个数,
但是问题是如果有一个入度为0的点缩点前只有1个点
且它的出边上的所有点都可以被其它入度为0的点遍历,
那么可以将其它点全部排除后剩下的这个点就是凶手,概率要加1
代码
#include <cstdio>
#include <cctype>
#include <map>
#include <stack>
#define rr register
using namespace std;
const int N=100011; struct node{int y,next;}e[N*5],E[N*5]; stack<int>stac; map<int,bool>uk[N];
int dfn[N],low[N],v[N],col[N],deg[N],as[N],hs[N],siz[N],m,ans,flag,Et,tot,cnt,n;
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans*f;
}
inline signed min(int a,int b){return a<b?a:b;}
inline void tarjan(int x){
dfn[x]=low[x]=++tot,
stac.push(x),v[x]=1;
for (rr int i=as[x];i;i=e[i].next)
if (!dfn[e[i].y]){
tarjan(e[i].y);
low[x]=min(low[x],low[e[i].y]);
}else if (v[e[i].y])
low[x]=min(low[x],dfn[e[i].y]);
if (dfn[x]==low[x]){
rr int y; ++cnt;
do{
y=stac.top(),stac.pop(),
col[y]=cnt,v[y]=0,++siz[cnt];
}while (x^y);
}
}
signed main(){
n=iut(),m=iut();
for (rr int i=1;i<=m;++i){
rr int x=iut(),y=iut();
e[i]=(node){y,as[x]},as[x]=i;
}
for (rr int i=1;i<=n;++i)
if (!dfn[i]) tarjan(i);
for (rr int i=1;i<=n;++i)
for (rr int j=as[i];j;j=e[j].next)
if (col[i]^col[e[j].y]){
if (uk[col[i]][col[e[j].y]]) continue;
uk[col[i]][col[e[j].y]]=1;
E[++Et]=(node){col[e[j].y],hs[col[i]]},
hs[col[i]]=Et,++deg[col[e[j].y]];
}
for (rr int i=1;i<=cnt;++i)
if (!deg[i]){
rr bool f=1; ++ans;
if (siz[i]>1) continue;
for (rr int j=hs[i];j;j=E[j].next)
if (deg[E[j].y]==1){
f=0;
break;
}
if (f) flag=1;
}
return !printf("%lf",(n-ans+flag)*1.0/n);
}