SCC指的是强连通分量,求SCC有三种高效的算法,即,他们的复杂度都是,但Kosaraju要差一点。
算法:
hdu 1269
一个有向图,有n个点和m条边,判断整个图是否强连通,如果是输出,否则输出。
手写一个栈,用的也行,我是用向前星存有向图。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=10005,maxm=100005; int cnt;//强连通分量(SCC)的个数 int low[maxn],num[maxn],dfn; int sccno[maxn],zhan[maxn],top; int head[maxn],Next[maxm],to[maxm],tot; inline void add(int u,int v) { to[tot]=v; Next[tot]=head[u]; head[u]=tot; } void dfs(int u) { zhan[top++]=u;//u进栈 low[u]=num[u]=++dfn; for(int i=head[u];i;i=Next[i]) { int v=to[i]; if(!num[v]) { dfs(v);//访问到DFS的最后一层,是最后一个SCC,或者是一个SCC的最后一个元素 low[u]=min(low[v],low[u]);//他可能有多个儿子,儿子如果和它不是一个SCC, //只有儿子和它是一个SCC,low[v]才会小于等于low[u] }//为访问过的点,继续DFS else if(!sccno[v]) low[u]=min(low[u],num[v]); //访问过的点可能是已经处理过的SCC上的点(还可能有重边) } if(low[u]==num[u]) { ++cnt; while(1){ int v=zhan[--top]; sccno[v]=cnt; if(u==v) break;//栈底的点是SCC的祖先,它low[u]==num[u] } } } void Tarjan(int n) { cnt=top=dfn=0; fill(sccno,sccno+maxn,0); fill(num,num+maxn,0); fill(low,low+maxn,0); for(int i=1;i<=n;++i) if(!num[i]) dfs(i); } int main() { int n,m,u,v; while(scanf("%d%d",&n,&m),n) { fill(head,head+maxn,0); for( tot=1;tot<=m;++tot ) { scanf("%d%d",&u,&v); add(u,v); } Tarjan(n); printf("%s\n",cnt==1?"Yes":"No"); } return 0; }