1. 程式人生 > >Tarjan求強連通分量、求橋和割點模板

Tarjan求強連通分量、求橋和割點模板

idg tar min article 每一個 ace from names struct

Tarjan 求強連通分量模板、參考博客

技術分享圖片
#include<stdio.h>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 1e3 + 10;
const int maxm = 330000 + 10;
struct EDGE{ int v, nxt; }Edge[maxm];
int Head[maxn], cnt;
int DFN[maxn], LOW[maxn], color[maxn], INDEX, id;
bool vis[maxn];
int N, M;
stack
<int> stk; inline void init() { while(!stk.empty()) stk.pop(); for(int i=0; i<=N; i++) Head[i] = DFN[i] = LOW[i] = color[i] = -1, cnt = INDEX = id = 0; } inline void AddEdge(int from, int to) { Edge[cnt].v = to; Edge[cnt].nxt = Head[from]; Head[from] = cnt++; } inline
void tarjan(int u) { DFN[u] = LOW[u] = INDEX++; stk.push(u); vis[u] = true; for(int i=Head[u]; i!=-1; i=Edge[i].nxt){ int Eiv = Edge[i].v; if(DFN[Eiv] == -1){ tarjan(Eiv); LOW[u] = min(LOW[u], LOW[Eiv]); }else{ if(vis[Eiv]) LOW[u]
= min(LOW[u], LOW[Eiv]); } } if(DFN[u] == LOW[u]){ color[u] = ++id; vis[u] = false; while(stk.top() != u){ vis[stk.top()] = false; color[stk.top()] = id; stk.pop(); } stk.pop(); } } int main(void) { while(~scanf("%d %d", &N, &M)){ init(); int from, to; while(M--){ scanf("%d %d", &from, &to); AddEdge(from, to); } for(int i=0; i<N; i++) if(DFN[i] == -1) tarjan(i); printf("%d\n\n", id); } return 0; }
View Code

Tarjan 求橋和割點模板

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;///圖中頂點的數量
const int maxm = 4e5 + 10;///圖中邊的數量
struct EDGE{ int v, nxt; }Edge[maxm];
int Head[maxn], cnt;///表頭以及邊的編號
int LOW[maxn], DFN[maxn];///每個點最早可回溯到的祖先節點、每個點的遍歷序號
int Fa[maxn], INDEX;///Fa數組記錄每一個點的父親、INDEX是算法裏的時間戳
int N, M;

inline void init()
{
    for(int i=0; i<=N; i++)
        Head[i] = LOW[i] = DFN[i] = -1, Fa[i] = 0;
    cnt = INDEX = 0;
}

inline void AddEdge(int from, int to)
{
    Edge[cnt].v = to;
    Edge[cnt].nxt = Head[from];
    Head[from] = cnt++;
}

void Tarjan(int v, int Father)
{
    Fa[v] = Father;
    DFN[v] = LOW[v] = INDEX++;
    for(int i=Head[v]; i!=-1; i=Edge[i].nxt){
        int Eiv = Edge[i].v;
        if(DFN[Eiv] == -1){
            Tarjan(Eiv, v);
            LOW[v] = min(LOW[v], LOW[Eiv]);
        }
        else if(Father != Eiv)
            LOW[v] = min(LOW[v], DFN[Eiv]);
    }
}

///這份代碼中頂點編號是從 0 ~ N-1
void Count()///統計割點和橋
{
    Tarjan(0, -1);

    int Cut_Num = 0;///割點的數量
    int Root_Child  = 0;///根節點的兒子
    Tarjan(0, -1);
    for(int i=1; i<N; i++){
        int v = Fa[i];
        if(v == 0) Root_Child++;
        else if(LOW[i] >= DFN[v] && !is_cut[v])
            is_cut[v] = true, Cut_Num++;
    }
    if(Root_Child > 1)
        is_cut[0] = true, Cut_Num++;///根節點有超過一個兒子則說明也是割點

    for(int i=0; i<N; i++){
        int v = Fa[i];
        if(v >= 0 && LOW[i] > DFN[v]){
            // v->i is bridge
            //可以用一個 pair<int, int> 來記錄
        }
    }
}

int main(void)
{
    while(~scanf("%d %d", &N, &M)){
        init();
        int from, to;
        while(M--){
            scanf("%d %d", &from, &to);
            AddEdge(from, to);
            AddEdge(to, from);
        }
        Count();
    }
    return 0;
}
View Code

Tarjan求強連通分量、求橋和割點模板