SCC的奇葩算法——Kosaraju

  不会Tarjan,难道就不能与邪恶的SCC作斗争了吗?

  祭出Kosaraju。

  一些变量名的意义:

  a[N] 原图的vector存储

  b[N] 原图的所有边反向vector存储

  s dfs得出的拓扑序列栈

  c[[N] 每个点的SCC编号

  算法框架:

  1.将原图做一遍类似于拓扑的dfs,越早访问的顶点压在一个栈中。

  2.不断从栈顶取出一个未访问过的点,对它的反向图再进行dfs,所有它能到达的未访问过的点就是他的SCC。

  3.这样就得到的一个图的SCC。

  对于2的正确性,应为这个点必被在栈中比它早入栈的点给压入栈,而且在栈中比它更上面的点已经被访问过,所以它在它下面能找到的点都是他的SCC(同时还避免了重复)

  CODE

  核心的两遍dfs

inline void dfs(int k)
{
    f[k]=0;
    for (int i=0;i<a[k].size();++i)
    if (f[a[k][i]]) dfs(a[k][i]);
    s.push_back(k);
}
inline void rdfs(int k)
{
    f[k]=0;
    c[k]=tot;
    t[tot]++;
    for (int i=0;i<b[k].size();++i)
    if (f[b[k][i]]) rdfs(b[k][i]);
}

  在主程序中只要:

    memset(f,true,sizeof(f));
   for (i=1;i<=n;++i)
    if (f[i]) dfs(i);
    memset(f,true,sizeof(f));
    for (i=s.size()-1;i>=0;--i)
    if (f[s[i]]) ++tot,rdfs(s[i]);

  复杂度为O(|V|+|E|) 虽然跑得没有Tarjan快,但是个人认为很容易理解。

原文地址:https://www.cnblogs.com/cjjsb/p/8137581.html