tarjan强连通分量缩点模板

强连通定义

百度百科 强连通图(Strongly Connected Graph):是指在有向图G中,如果对于每一对vi、vj,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称做有向图的强连通分量。

缩点

在算法竞赛中,将强连通分量(例如环)处理成点会减少很多工作量。

在这里插入图片描述

上图中,1、3、5、2、6是一个强连通分量,经过缩点之后,变成下图。

在这里插入图片描述

tarjan算法

概念

从图中一点作为起点,进行DFS搜索遍历图,这样会得到一棵树,我们称之为DFS搜索树,该树中的每一条边都来自原图,我们将这些边称为树边,其他图中的边称为非树边

DFN数组:记录DFS序,也即时间戳、搜索顺序。
LOW数组:记录每个点经过一条非树边能回到的所有结点的最小DFN值注意,low值不同的点也可能属于一个强连通分量

求解

强连通图有如下性质,从图中一点出发,能经过所有点返回到起点。可以利用以上性质,结合深度优先搜索,如果某一时刻搜索到了一个被标记过的点,那么这一个回路上的点都属于同一个强连通分量。

代码实现

#include <iostream>
#include <stack>
#include <vector>
using namespace std;

const int N = 105;
int n, m;
vector<int> edge[N];
vector<int> belong[N]; //同一个强连通分量中的点
int dfn[N];            //dfs序
int root[N];           //强连通分量的根结点
int cnt;               //强连通分量数量
int ct;
stack<int> st;
bool instack[N];
void tarjan(int pos)
{
    dfn[pos] = ++cnt;
    root[pos] = cnt;
    st.emplace(pos);
    instack[pos] = 1;
    for (auto v : edge[pos])
    {
        if (!dfn[v])
        {
            tarjan(v);
            root[pos] = min(root[pos], root[v]);
        }
        else if (instack[v])
            /*
        到达一个标记过而且还在栈中的点,
        那么这一个回路都同属于一个强连通分量
        */
            root[pos] = min(root[pos], dfn[v]);
    }

    if (root[pos] == dfn[pos])
    {
        ++ct;
        int node;
        do
        {
            node = st.top();
            st.pop();
            instack[node] = 0;
            belong[ct].emplace_back(node);
        } while (root[node] != dfn[node]);
    }
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; ++i)
    {
        int u, v;
        cin >> u >> v;
        edge[u].push_back(v);
    }

    for (int i = 1; i <= n; i++)
        if (!dfn[i]) //图不一定连通
            tarjan(i);
    for (int i = 1; i <= n; i++)
        cout << i << ' ' << dfn[i] << endl;
    cout << ct << endl;
    for (int i = 1; i <= ct; i++)
        for (auto it : belong[i])
            cout << it << " belong to " << i << endl;
    return 0;
}
/*
7 9
1 3
5 1
1 6
2 5
6 2
3 4
3 5
5 6
2 7
*/

参考资料

  1. 图论——强连通分量(Tarjan算法)

  2. tarjan算法详解–关于图的连通性 & 连通分量

  3. 算法学习笔记(69): 强连通分量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值