Tarjan总结

Tarjan算法基于深度优先遍历, 可在\(O(n)\)的时间复杂度下处理问题

一. Tarjan算法在无向图上的应用:

1.Tarjan求桥

struct Tarjan_Bridge //无向图 桥
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1];
    int head[maxn], tot = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    int dfn[maxn], low[maxn], Time;
    bool bridge[maxn];
    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        fort(u)
        {
            if(v == fa) continue;
            if(!dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    bridge[i]= bridge[i ^ 1] = true;
            }
            else
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i, 0);
            }
        }
        return;
    }
}T_bridge;

2. Tarjan算法求割点

struct Tarjan_Cut //无向图 割点
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1];
    int head[maxn], tot = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    int dfn[maxn], low[maxn], Time;
    int root;
    bool cut[maxn];

    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        int flag = 0;
        fort(u)
        {
            if (v == fa) continue;
            if(! dfn[v]) 
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {
                    flag ++;
                    if(u != root || flag > 1)   
                        cut[u] = true;
                }
                else
                {
                    low[u] = min(low[u], dfn[v]);
                }
            }
        }
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                root = i;
                Tarjan(i, 0);
            }
        }
        return;
    }
}T_cut;

3. Tarjan算法求e_DCC

struct Tarjan_e_DCC //无向图 边双联通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time;
    int bel[maxn], tot_dcc;
    bool bridge[maxn];
    void Tarjan_bridge(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        fort(u)
        {
            if(v == fa) continue;
            if(!dfn[v])
            {
                Tarjan_bridge(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    bridge[i]= bridge[i ^ 1] = true;
            }
            else
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        return;
    }
    void Dfs(int u)
    {
        bel[u] = tot_dcc;
        fort(u)
        {
            if(bel[v] || bridge[i]) continue;
            Dfs(v);
        }
        return;
    }
    void SD_e_DCC()
    {
        for (int i = 2; i <= tot; ++ i)
        {
            int u = e[i ^ 1].to, v = e[i].to;
            if(bel[u] == bel[v]) continue;
            Insertg(bel[u], bel[v]);
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(!dfn[i])
            {
                Tarjan_bridge(i, 0);
            }
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! bel[i])
            {
                ++ tot_dcc, Dfs(i);
            }
        }
        SD_e_DCC();
        return;
    }
}T_e_DCC;

Tarjan算法求v_DCC

struct Tarjan_v_DCC //无向图 点双联通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time; 
    int stk[maxn], top;
    int root;
    bool cut[maxn];
    int num, new_id[maxn], bel[maxn];
    vector <int> dcc[maxn];
    int tot_dcc;

    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        stk[++ top] = u;
        if(u == root && head[u] == 0)
        {
            dcc[++ tot_dcc].push_back(u);
            return;
        }
        int flag = 0;
        fort(u)
        {
            if(v == fa) continue;
            if(! dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {//考Tarjan e_DCC 的比赛
                    flag ++;
                    if(u != root || flag > 1) cut[u] = true;
                    tot_dcc ++;
                    while(stk[top + 1] != v)
                    {
                        dcc[tot_dcc].push_back(stk[top --]);
                    }
                }
                else
                {
                    low[u] = min(low[u], dfn[v]);
                }
            } 
        }
        return;
    }
    void SD_v_DCC()
    {
        num = tot_dcc;
        for (int i = 1; i <= n; ++ i)
        {
            if(cut[i])
            {
                new_id[i] = ++ num;
            }
        }
        for (int i = 1; i <= tot_dcc; ++ i)
        {
            for (int j = 0; j < dcc[i].size(); ++ j)
            {
                int x = dcc[i][j];
                if(cut[x])
                {
                    Insertg(i, new_id[x]), Insertg(new_id[x], i);
                }
                else
                {
                    bel[x] = i;
                }
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i, 0);
            }
        }
        SD_v_DCC();
        return;
    }
}T_v_DCC;

二. Tarjan算法在有向图上的应用:

Tarjan算法求SCC

struct Tarjan_SCC //有向图 强连通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time;
    int stk[maxn], top;
    bool inv[maxn];
    int tot_scc, bel[maxn];
    vector <int> scc[maxn];

    void Tarjan(int u)
    {
        dfn[u] = low[u] = ++ Time;
        stk[++ top] = u, inv[u] = true;
        fort(u)
        {
            if(!dfn[v])
            {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(inv[v])
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u])
        {
            ++ tot_scc;
            while(stk[top + 1] != u)
            {
                int v = stk[top];
                inv[v] = false;
                bel[v] = tot_scc;
                scc[tot_scc].push_back(v);
            }
        }
        return;
    }
    void SD_SCC()
    {
        for (int u = 1; u <= n; ++ u)
        {
            fort (u)
            {
                if(bel[u] == bel[v]) continue;
                Insert(bel[u], bel[v]);
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i);
            }
        }
        SD_SCC();
        return;
    }
}T_SCC;
点击查看代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <bitset>
#include <cstdio>
#include <cmath>
#include <queue>

using namespace std;

#define ull unsigned long long
#define rint register int
#define ll long long
#define dd double
// #define int long long
#define fort(x) for (int i = head[x], v = e[i].to; i; i = e[i].next, v = e[i].to)

const int INF = 0x3f, INFF = 0x3f3f3f3f, INFFF = 0x7fffffff;
const int maxn = 3e6 + 5, maxm = 1e3 + 5;

int n, m;

int read()
{
    int x = 0, w = 0; char ch = getchar();  
    while(ch <  '0' || ch >  '9'){ if(ch == '-') w = 1; ch = getchar(); }
    while(ch >= '0' && ch <= '9'){ x = (x << 1) + (x << 3) + (ch ^ '0'); ch = getchar(); }
    if(w) return -x; return x;
}
struct Tarjan_Bridge //无向图 桥
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1];
    int head[maxn], tot = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    int dfn[maxn], low[maxn], Time;
    bool bridge[maxn];
    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        fort(u)
        {
            if(v == fa) continue;
            if(!dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    bridge[i]= bridge[i ^ 1] = true;
            }
            else
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i, 0);
            }
        }
        return;
    }
}T_bridge;
struct Tarjan_Cut //无向图 割点
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1];
    int head[maxn], tot = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    int dfn[maxn], low[maxn], Time;
    int root;
    bool cut[maxn];

    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        int flag = 0;
        fort(u)
        {
            if (v == fa) continue;
            if(! dfn[v]) 
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {
                    flag ++;
                    if(u != root || flag > 1)   
                        cut[u] = true;
                }
                else
                {
                    low[u] = min(low[u], dfn[v]);
                }
            }
        }
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                root = i;
                Tarjan(i, 0);
            }
        }
        return;
    }
}T_cut;
struct Tarjan_v_DCC //无向图 点双联通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time; 
    int stk[maxn], top;
    int root;
    bool cut[maxn];
    int num, new_id[maxn], bel[maxn];
    vector <int> dcc[maxn];
    int tot_dcc;

    void Tarjan(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        stk[++ top] = u;
        if(u == root && head[u] == 0)
        {
            dcc[++ tot_dcc].push_back(u);
            return;
        }
        int flag = 0;
        fort(u)
        {
            if(v == fa) continue;
            if(! dfn[v])
            {
                Tarjan(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {//考Tarjan e_DCC 的比赛
                    flag ++;
                    if(u != root || flag > 1) cut[u] = true;
                    tot_dcc ++;
                    while(stk[top + 1] != v)
                    {
                        dcc[tot_dcc].push_back(stk[top --]);
                    }
                }
                else
                {
                    low[u] = min(low[u], dfn[v]);
                }
            } 
        }
        return;
    }
    void SD_v_DCC()
    {
        num = tot_dcc;
        for (int i = 1; i <= n; ++ i)
        {
            if(cut[i])
            {
                new_id[i] = ++ num;
            }
        }
        for (int i = 1; i <= tot_dcc; ++ i)
        {
            for (int j = 0; j < dcc[i].size(); ++ j)
            {
                int x = dcc[i][j];
                if(cut[x])
                {
                    Insertg(i, new_id[x]), Insertg(new_id[x], i);
                }
                else
                {
                    bel[x] = i;
                }
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i, 0);
            }
        }
        SD_v_DCC();
        return;
    }
}T_v_DCC;
struct Tarjan_e_DCC //无向图 边双联通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time;
    int bel[maxn], tot_dcc;
    bool bridge[maxn];
    void Tarjan_bridge(int u, int fa)
    {
        dfn[u] = low[u] = ++ Time;
        fort(u)
        {
            if(v == fa) continue;
            if(!dfn[v])
            {
                Tarjan_bridge(v, u);
                low[u] = min(low[u], low[v]);
                if(low[v] > dfn[u])
                    bridge[i]= bridge[i ^ 1] = true;
            }
            else
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        return;
    }
    void Dfs(int u)
    {
        bel[u] = tot_dcc;
        fort(u)
        {
            if(bel[v] || bridge[i]) continue;
            Dfs(v);
        }
        return;
    }
    void SD_e_DCC()
    {
        for (int i = 2; i <= tot; ++ i)
        {
            int u = e[i ^ 1].to, v = e[i].to;
            if(bel[u] == bel[v]) continue;
            Insertg(bel[u], bel[v]);
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v), Insert(v, u);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(!dfn[i])
            {
                Tarjan_bridge(i, 0);
            }
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! bel[i])
            {
                ++ tot_dcc, Dfs(i);
            }
        }
        SD_e_DCC();
        return;
    }
}T_e_DCC;
struct Tarjan_SCC //有向图 强连通分量
{
    struct Edge
    {
        int to, next;
    }e[maxn << 1], g[maxn << 1];
    int head[maxn], tot = 1;
    int headg[maxn], totg = 1;
    void Insert(int u, int v)
    {
        return (void)(e[++ tot].to = v, e[tot].next = head[u], head[u] = tot);
    }
    void Insertg(int u, int v)
    {
        return (void)(g[++ totg].to = v, g[totg].next = headg[u], headg[u] = totg);
    }
    int dfn[maxn], low[maxn], Time;
    int stk[maxn], top;
    bool inv[maxn];
    int tot_scc, bel[maxn];
    vector <int> scc[maxn];

    void Tarjan(int u)
    {
        dfn[u] = low[u] = ++ Time;
        stk[++ top] = u, inv[u] = true;
        fort(u)
        {
            if(!dfn[v])
            {
                Tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(inv[v])
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if(dfn[u] == low[u])
        {
            ++ tot_scc;
            while(stk[top + 1] != u)
            {
                int v = stk[top];
                inv[v] = false;
                bel[v] = tot_scc;
                scc[tot_scc].push_back(v);
            }
        }
        return;
    }
    void SD_SCC()
    {
        for (int u = 1; u <= n; ++ u)
        {
            fort (u)
            {
                if(bel[u] == bel[v]) continue;
                Insert(bel[u], bel[v]);
            }
        }
        return;
    }
    void work()
    {
        for (int i = 1; i <= m; ++ i)
        {
            int u = read(), v = read();
            Insert(u, v);
        }
        for (int i = 1; i <= n; ++ i)
        {
            if(! dfn[i])
            {
                Tarjan(i);
            }
        }
        SD_SCC();
        return;
    }
}T_SCC;
void Solve()
{
    return;
}
// #undef int
int main()
{   
    Solve();
    return 0;
}
posted @ 2022-10-17 12:16  Eakang  阅读(61)  评论(8编辑  收藏  举报