分析:首先,在一个有向无环图中,能被所有点达到点,出度一定是0。
先求出所有的强连通分支,然后把每个强连通分支收缩成一个点,重新建图,这样,这个有向图就变成了一个有向无环图。
在这个新的图中,只需知道出度为0的点有几个即可。
如果出度为0的点超过1个,则输出0;否则输出出度为0的点所代表的那个强连通分支的分量数即可。
用Tarjan求强连通分量
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <string> #include <vector> #include <stack> using namespace std; #define N 10007 vector<int> G[N],G2[N]; stack<int> stk; int instk[N],cnt,Time,n,m,out[N]; int low[N],dfn[N],bel[N],num[N]; void tarjan(int u) { low[u] = dfn[u] = ++Time; stk.push(u); instk[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(instk[v]) low[u] = min(low[u],dfn[v]); } if(low[u] == dfn[u]) { cnt++; int v; do { v = stk.top(); stk.pop(); instk[v] = 0; bel[v] = cnt; num[cnt]++; }while(u != v); } } void Tarjan() { memset(bel,0,sizeof(bel)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(instk,0,sizeof(instk)); memset(num,0,sizeof(num)); memset(out,0,sizeof(out)); while(!stk.empty()) stk.pop(); Time = cnt = 0; for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); } void Build() { int i,j; for(i=0;i<=cnt;i++) G2[i].clear(); for(i=1;i<=n;i++) { for(j=0;j<G[i].size();j++) { int v = G[i][j]; if(bel[i] != bel[v]) { G2[bel[i]].push_back(bel[v]); out[bel[i]]++; } } } } int main() { int i,j,u,v; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<=n;i++) G[i].clear(); for(i=0;i<m;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); } Tarjan(); Build(); int ans = 0; int flag = 0; int tag = 1; for(i=1;i<=cnt;i++) { if(out[i]) continue; if(flag) { tag = 0; break; } else { ans += num[i]; flag = 1; } } if(!tag) puts("0"); else printf("%d\n",ans); } return 0; }
POJ 2186 Popular Cows --强连通分量,布布扣,bubuko.com
原文:http://www.cnblogs.com/whatbeg/p/3836601.html