初学强连通(Tarjan)

首先我们要对强连通分量有个定义,何为强连通?

  如果一个图的子图中,任意两点可以相互到达,那么这就组成了一个强连通分量。

  一般强连通都是在有向图的情况下讨论的,因为在无向图中只要这个图连通这整个图就是一个强连通图,而在有向图中,只有子图成环,才会出现强连通分量的情况,因此tarjan缩点算法一般用于处理成环有向图的问题。

Tarjan算法思想

  Tarjan算法是基于对图深度优先搜索的算法。首先要理解的是两个数组:dfn 数组和 low 数组,其中 dfn 数组是代表第 i 个节点在 dfs 序上是第几个被遍历到,low [u] 则表示为以 u 为起点进行 dfs 所能经过点中最小的 dfs 序,即最小的 dfn [i],所以当 dfn [u] == low [u]时,说明出现环了,这时换种任意一点都能到达环上其他点,因此这就是个强连通分量。

  图解(转自https://www.cnblogs.com/five20/p/7594239.html

算法模板

int deep,num;
int dfn[MAXN],low[MAXN],vis[MAXN],col[MAXN];
vector<int>G[MAXN];
stack<int>s;
inline void Tarjan(int u){
    deep++;
    dfn[u]=low[u]=deep;
    vis[u]=1;
    s.push(u);
    for(auto v:G[u]){
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        col[u]=++num;
        vis[u]=0;
        while(s.top()!=u){
            col[s.top()]=num;
            vis[s.top()]=0;
            s.pop();
        }
        s.pop();
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])Tarjan(i);
    for(int i=1;i<=n;i++)
        printf("******%d %d
",i,col[i]);
    //最后的col数组就代表缩完点后每个点的归属
}
原文地址:https://www.cnblogs.com/Mmasker/p/12011642.html