最近考试又跪了,好忧桑。
tarjan求一遍强连通分量,然后只需要算入度为0的块就可以了。
还有一种情况我没有想到,就是如果其他块都确定了,那么最后一个就不需要确定了。这种情况就是一个入度为0的块大小为1而且它指向的块都可以通过别的方式找到,这样的话这个点就不需要统计了。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #define maxn 100010 #define maxm 300010 using namespace std; int head[maxn],to[maxm],next[maxm]; int head1[maxn],to1[maxm],next1[maxm]; int n,m,scc,num,tot,top; int bel[maxn],size[maxn],d[maxn],dfn[maxn],low[maxn],s[maxn]; bool vis[maxn],flag[maxn]; void addedge(int x,int y) { num++;to[num]=y;next[num]=head[x];head[x]=num; } void addedge1(int x,int y) { d[y]++;num++;to1[num]=y;next1[num]=head1[x];head1[x]=num; } void tarjan(int x) { s[++top]=x; dfn[x]=low[x]=++tot; flag[x]=1; for (int p=head[x];p;p=next[p]) if (!dfn[to[p]]) { tarjan(to[p]); low[x]=min(low[x],low[to[p]]); } else if (flag[to[p]]) low[x]=min(low[x],dfn[to[p]]); if (dfn[x]==low[x]) { scc++; while (s[top+1]!=x) { flag[s[top]]=0; bel[s[top]]=scc; size[scc]++; top--; } } } void rebuild() { for (int i=1;i<=n;i++) for (int p=head[i];p;p=next[p]) if (bel[i]!=bel[to[p]]) addedge1(bel[i],bel[to[p]]); } bool check(int x) { if (d[x] || size[x]!=1) return 0; for (int p=head1[x];p;p=next1[p]) if (d[to1[p]]==1) return 0; return 1; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i); num=0; rebuild(); int tot=0; for (int i=1;i<=scc;i++) if (!d[i]) tot++; for (int i=1;i<=n;i++) if (check(i)) {tot--;break;} printf("%.6lf\n",(n-tot)/(double)n); return 0; }