有向图的强连通分量——Tarjan

在同一个DFS树中分离不同的强连通分量SCC;

考虑一个强连通分量C,第一个被发现的点是 x,希望在 x 访问完时立刻输出 C,这样就可以实现 在同一个DFS树中分离不同的强连通分量了。

问题就转换为判断,一个点是否 是 第一个被发现的点,这样,可以利用之前的 点-双连通分离的数据结构, lowlink(u) 函数,为 u 及其后代能追溯到的最早祖先。

当 lowlink(u) == pre[u] (进树的时间),那么这个点 U 就是第一个被发现的点。那么这个 强连通分量就出来了。

#include <bits/stdc++.h>
using namespace std;

const int Maxn = 1000;

vector<int> G[Maxn];
int pre[Maxn];
int lowlink[Maxn];
int sccno[Maxn];
int dfs_clock,scc_cnt;

stack<int> S;   //点集

void dfs(int u)
{
    lowlink[u] = pre[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);
            lowlink[u] = min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u] = min(lowlink[u],pre[v]);
        }
    }
    if(lowlink[u]==pre[u])
    {
        scc_cnt ++;
        for(;;)
        {
            int x = S.top();
            S.pop();
            sccno[x] = 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);
}
原文地址:https://www.cnblogs.com/TreeDream/p/6075246.html