tarjan强连通分量缩点模板
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan强连通分量缩点模板相关的知识,希望对你有一定的参考价值。
强连通定义
百度百科 强连通图(Strongly Connected Graph):是指在有向图G中,如果对于每一对vi、vj,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称做有向图的强连通分量。
缩点
在算法竞赛中,将强连通分量(例如环)处理成点会减少很多工作量。
上图中,1、3、5、2、6是一个强连通分量,经过缩点之后,变成下图。
tarjan算法
强连通图有如下性质,从图中一点出发,能经过所有点返回到起点。
可以利用以上性质,结合深度优先搜索,如果某一时刻搜索到了一个被标记过的点,那么这一个回路上的点都属于同一个强连通分量。
代码实现
#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
*/
参考资料
以上是关于tarjan强连通分量缩点模板的主要内容,如果未能解决你的问题,请参考以下文章