题目
一开始想到的是求出强连通,进行缩点后,统计入度为强连通个数-1的点,然后累加其中的点个数。
发现下面这组测试数据无法通过。如果仍采用这种做法的话还需要进行拓扑排序??
5 5
1 2
2 3
3 1
1 4
4 5
更简单的方法是统计出度为0的点。如果个数为1,则答案就是该点所包含的点个数;否则为0(多于1个说明不连通)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<stack> using namespace std; #define N 100005 vector<int> G[N]; int pre[N],low[N],sccno[N],dfs_clock,scc_cnt,cnt[N]; stack<int>S; void dfs(int u){ pre[u]=low[u]=++dfs_clock; S.push(u); for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(!pre[v]){ dfs(v); low[u]=min(low[u],low[v]); }else if(!sccno[v]) low[u]=min(low[u],pre[v]); } if(low[u]==pre[u]){ cnt[++scc_cnt]=0; for(;;){ int x=S.top();S.pop(); sccno[x]=scc_cnt; ++cnt[scc_cnt]; if(x==u) break; } } } void find_scc(int n){ dfs_clock=scc_cnt=0; memset(sccno,0,sizeof(sccno)); memset(pre,0,sizeof(pre)); for(int i=0;i<n;++i) if(!pre[i]) dfs(i); } int out[N]; int main() { int n,m,i,x,y,j; while(~scanf("%d%d",&n,&m)){ for(i=0;i<n;++i) G[i].clear(); while(m--){ scanf("%d%d",&x,&y); G[--x].push_back(--y); } find_scc(n); int ans=0,tot=0; for(i=1;i<=scc_cnt;++i)out[i]=0; for(i=0;i<n;++i) for(j=0;j<G[i].size();++j){ int v=G[i][j]; if(sccno[v]!=sccno[i]) ++out[sccno[i]]; } for(i=1;i<=scc_cnt;++i) if(!out[i]) {++tot;ans+=cnt[i];} printf("%d\n",tot==1?ans:0); } return 0; }