题解:
tarjan+概率
首先tarjan缩点
然后计算一个x,计算方法:
1.每当有一个强连通分量i的入度为0,那么x++
2.如果有一个强连通分量i,它的入度为0,且它连的每一条边只有他连,那么x-1
答案就是(n-x)/n
代码:
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=3e5+5; int dfn[N],num[N],low[N],x,y,an[N],cnt,fi[N]; int zz[M],ne[M],f[M],k,size[N],n,m,r[N],a[N],t,l; int jb(int x,int y) { zz[++k]=y; f[k]=x; ne[k]=fi[x]; fi[x]=k; } int dfs(int u) { dfn[u]=low[u]=++l; a[++t]=u; for(int i=fi[u];i;i=ne[i]) if(!dfn[zz[i]]) { dfs(zz[i]); low[u]=min(low[u],low[zz[i]]); } else if(!an[zz[i]])low[u]=min(low[u],dfn[zz[i]]); if(low[u]==dfn[u]) { num[++cnt]=u; while(t) { an[a[t]]=cnt; size[cnt]++; if(a[t--]==u) break; } } } int pd(int x) { int u=num[x]; for(int i=fi[u];i;i=ne[i]) if(r[an[zz[i]]]==1)return 0; return 1; } int main() { scanf("%d%d",&n,&m); while (m--) { scanf("%d%d",&x,&y); jb(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); for(int i=1;i<=k;i++) if(an[f[i]]!=an[zz[i]]) r[an[zz[i]]]++; int ans=0; for(int i=1;i<=cnt;i++) if(!r[i]) ans++; for(int i=1;i<=cnt;i++) if(size[i]==1&&!r[i]&&pd(i)) { ans--; break; } printf("%.6lf",(double)(n-ans)/n); return 0; }