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;
}