首页 > 代码库 > 【连通图|双连通】双连通分量 Tarjan

【连通图|双连通】双连通分量 Tarjan

/*
 * ID: j.sure.1
 * PROG:
 * LANG: C++
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <climits>
#include <iostream>
#define Mem(f, x) memset(f, x, sizeof(f))
#define PB push_back
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
/****************************************/
const int N = 1e5, M = 1e5;
struct Pair {
    int u, v;
    Pair(){}
    Pair(int _u, int _v):
        u(_u), v(_v){}
};
struct Edge {
    int v, next;
    Edge(){}
    Edge(int _v, int _next):
        v(_v), next(_next){}
}e[M];
int dfn[N], iscut[N], color[N], head[N];
stack <Pair> s;
int bcc, deep;

void add(int u, int v)
{
    e[tot] = Edge(v, head[u]);
    head[u] = tot++;
}

int dfs(int u, int fa)
{
    int lowu = dfn[u] = ++deep;
    int son = 0; 
    for(int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        Pair p = Pair(u, v);
        if(!dfn[v]) {//儿子
            s.push(p);//和儿子的边进栈
            son++;
            int lowv = dfs(v, u);
            lowu = min(lowu, lowv);
            if(lowv >= dfn[u]) {//条件成立时,说明走出关节点u会进入另一个连通分量
                iscut[u] = 1;
                bcc++;
                while(1){
                    Pair x = s.top(); s.pop();//因此在此之前将u的所有分量染色
                    if(color[x.u] != bcc) color[x.u] = bcc;
                    if(color[x.v] != bcc) color[x.v] = bcc;
                    if(x.u == u && x.v == v) break;
                }
            }
        }
        else if(dfn[v] < dfn[u] && v != fa) {//回边
            s.push(p);
            lowu = min(lowu, dfn[v]);
        }
    }
    if(fa == -1 && son == 1) iscut[u] = 0;
    return lowu;
}

void tarjan(int n)
{
    for(int i = 0; i < n; i++) {
        dfn[i] = iscut[i] = color[i] = 0;
        head[i] = -1;
    }
    tot = deep = bcc = 0;
    for(int i = 0; i < n; i++) {//为防止图不连通
        if(!dfn[i]) dfs(i, -1);
    }
}


int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif

    return 0;
}

【连通图|双连通】双连通分量 Tarjan