题意:就是判断一个图是否为弱连通图。
思路:先用tarjan处理一遍找出强连通分量。然后将每个强连通分量缩点,形成一个有向无环图。
如果该有向无环图是一个无分叉的树的话,即是弱连通图。
如果有分叉,则分叉两端的节点无法互相到达,即不是弱连通图。
#include<iostream> #define min(a,b) (a<b?a:b) using namespace std; const int N=1005,M=6005; int n,m; int edgehead[N]; struct Edge { int v,next; }edge[M]; int indegree[N]; int outdegree[N]; bool instack[N]; int dfn[N],low[N]; int k=1; void addedge(int u,int v) { edge[k].v=v; edge[k].next=edgehead[u]; edgehead[u]=k++; } int stack[N]; int sp=0; int index=0; int headsta[N]; int ph=0; int father[N]; void tarjan(int i) { dfn[i]=low[i]=++index; instack[i]=true; stack[sp++]=i; for(int j=edgehead[i];j;j=edge[j].next) { int v=edge[j].v; if(!dfn[v]) { tarjan(v); low[i]=min(low[i],low[v]); } else if(instack[v]) { low[i]=min(low[i],dfn[v]); } } if(dfn[i]==low[i]) { headsta[ph++]=i; int ans; do { ans=stack[--sp]; father[ans]=i; instack[ans]=false; }while(ans!=i); } } bool vis[N]; int sum; bool dfs(int root,int w) { if(w==sum) return true; for(int i=edgehead[root];i;i=edge[i].next) { int v=edge[i].v; if(father[v]!=father[root]&&!vis[v]) { vis[v]=true; return dfs(v,w+1); } } return false; } void solve() { for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++) { for(int j=edgehead[i];j;j=edge[j].next) { if(father[edge[j].v]!=father[i]) { indegree[father[edge[j].v]]++; outdegree[father[i]]++; } } } sum=ph; while(ph>0) { int now=headsta[--ph]; if(indegree[now]==0) { vis[now]=true; if(dfs(now,1)) printf("Yes\n"); else printf("No\n"); break; } } } int main() { int cases; scanf("%d",&cases); while(cases--) { k=1; memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(edge,0,sizeof(edge)); memset(edgehead,0,sizeof(edgehead)); memset(instack,0,sizeof(instack)); memset(headsta,0,sizeof(headsta)); memset(indegree,0,sizeof(indegree)); memset(outdegree,0,sizeof(outdegree)); memset(father,0,sizeof(father)); sp=0; ph=0; index=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int from,to; scanf("%d%d",&from,&to); addedge(from,to); } solve(); } return 0; }