首页 > 其他分享 >Tarjan总结

Tarjan总结

时间:2022-10-17 12:22:34浏览次数:49  
标签:总结 Tarjan int dcc ++ dfn low

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;
}

标签:总结,Tarjan,int,dcc,++,dfn,low
From: https://www.cnblogs.com/Eakang/p/16798779.html

相关文章

  • 【多线程总结(一)-基础总结】
    前言:多线程在我们的程序开发过程中起着关键的作用,本篇博客咱们从基本的知识开始讲起,来共同分享一下多线程的知识核心:什么是线程呢?咱们首先可以从进程来说,进程是指......
  • 【多线程总结(二)-线程安全与线程同步】
    前言:继前一篇博客,今天咱们这篇博客来说说线程安全与线程同步那些事.核心:初识synchronized关键字可以实现一个简单的策略防止线程干扰和内存一致性错误,如果一个对象对......
  • 【多线程总结(四)-三大性质总结】
    前言在并发编程中分析线程安全的问题时三条性质:原子性,有序性和可见性往往是非常重要的,本篇博客主要来用synchronized和volatile关键来进行对比。首先来看看宏观导图核心原......
  • 9.5 模拟赛总结
    2021.09.05不知为何没点发布。根据昨天发生的状况,开考赶紧先把题都看了一遍,还好,都能看懂。\(T1\)的式子推了好半天,没推出来啥结论,于是把所有题的部分分都想了一下。\(T......
  • Java基础面试总结
    常见编译型语言:C、C++、Go、Rust等(执行速度快,但开发效率低)常见解释型语言:Python、JavaScript、PHP(开发效率高,但执行效率低)先编译后解释:Java重载和重写有什么区别?重载......
  • 每周总结14
    本周主要做了很多算法题,其中最经典的便是完全背包问题 #include<iostream>usingnamespacestd;constintN=1010;intmain(){intf[N]={0};......
  • 化学知识点总结
    初三上(链接)第一单元知识点(下载链接)第二单元知识点(下载链接)第三单元知识点(下载链接)第四单元知识点(下载链接) 。......
  • 本周内容总结
    文件操作文件的概念就是操作系统暴露给用户操作硬盘的快捷方式双击一个文件其实是从硬盘将数据加载到内存ctrl+s保存文件其实是将内存中的数据刷到硬盘保存......
  • 第三周总结
    本周总结本周内容详情文件操作文件的概念:操作系统暴露给用户操作硬盘的快捷方式文件打开的两种方式:f=open(文件路径,读写模式,encoding='utf8')f.closewithopen('a......
  • 2022-2023-1 20221317《计算机基础与程序设计》第六周学习总结
    作业信息这个作业属于哪个课程:首页-2022-2023-1-计算机基础与程序设计-北京电子科技学院-班级博客-博客园(cnblogs.com)这个作业的要求在:2022-2023-1《计算......