tarjan求割点和桥(割边)模板
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan求割点和桥(割边)模板相关的知识,希望对你有一定的参考价值。
tanjan算法相关概念
为了与有向图尽可能保持一致,我们将无向图的一条无向边拆分成两条单向边。两条边互为反向边。
从图中一点作为起点,进行DFS搜索遍历图,这样会得到一棵树,我们称之为DFS搜索树,该树中的每一条边都来自原图,我们将这些边称为树边,其他图中的边称为非树边。
DFN数组:记录DFS序,也即时间戳、搜索顺序。
LOW数组:记录每个点经过一条非树边能回到的所有结点的最小DFN值。
割点
割点集合:在一个无向图中,如果有一个顶点集合,删除这个顶点集合以及这个集合中所有顶点相关联的边以后,图的连通分量增多,就称这个点集为割点集合。
求解
设一个点 u u u,其父亲结点为 f u fu fu,如果有 L O W [ u ] > = D F N [ f u ] LOW[u] >= DFN[fu] LOW[u]>=DFN[fu],那么说明,点 u u u仅可以经过点 f u fu fu抵达,此时,如果删除点 f u fu fu,那么 u u u就和 f u fu fu所在的图不再连通, f u fu fu就是一个割点。
对于根结点而言是一种特殊情况,因为不可能有点的 L O W [ u ] LOW[u] LOW[u]会小于 D F N [ f u ] DFN[fu] DFN[fu]。根结点为割点当且仅当有 2 2 2个以上子节点时,只需特判即可。
tarjan求割点代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> edge[N];
int dfn[N], root[N];
int ct;
vector<int> cut_points;
void tarjan(int u, bool isroot)
{
int tot = 0;
root[u] = dfn[u] = ++ct;
for (auto v : edge[u])
{
if (!dfn[v])
{
tarjan(v, 0);
root[u] = min(root[u], root[v]);
tot += root[v] >= dfn[u];
}
else
root[u] = min(root[u], dfn[v]);
}
if ((isroot && tot >= 2) || (!isroot && tot >= 1))
cut_points.emplace_back(u);
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
edge[u].emplace_back(v);
edge[v].emplace_back(u);
}
tarjan(1, 1);
cout << "cut_points: ";
for (auto it : cut_points)
cout << it << ' ';
return 0;
}
/*
5 5
1 2
2 3
3 4
2 4
4 5
*/
割边
割边:假设有连通图G,e是其中一条边,如果G-e是不连通的,则边e是图G的一条割边。此情形下,G-e必包含两个连通分支。
和割点对应,删除一条割边后,连通分量加一。
求解
对LOW数组的定义略加修改:记录每个点经过一条非树边能回到的所有结点的最小DFN值,并且该非树边不可以是某条树边的反向边。
tarjan求割边代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> edge[N];
int dfn[N], root[N], fa[N], ct;
struct node
{
int u, v;
};
vector<node> cut_edge;
void tarjan(int u)
{
int tot = 0;
root[u] = dfn[u] = ++ct;
for (auto v : edge[u])
{
if (!dfn[v])
{
fa[v] = u;
tarjan(v);
root[u] = min(root[u], root[v]);
if (root[v] > dfn[u])
cut_edge.emplace_back(node{u, v});
}
else if (v != fa[u])
root[u] = min(root[u], dfn[v]);
}
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
edge[u].emplace_back(v);
edge[v].emplace_back(u);
}
tarjan(1);
cout << "cut_edge:\\n";
for (auto it : cut_edge)
cout << it.u << "--" << it.v << '\\n';
return 0;
}
/*
5 5
1 2
2 3
3 4
2 4
4 5
*/
参考资料
以上是关于tarjan求割点和桥(割边)模板的主要内容,如果未能解决你的问题,请参考以下文章