割边

DFS 生成树
对于一张连通的无向图,我们可以从任意一点开始 DFS,得到原图的一棵 DFS 生成树(以开始 DFS 的那个点为根),这棵生成树上的边称作 树边,不在生成树上的边称作 非树边。
无向图生成树里面只有树边和非树边(返祖边)。 (这里可以对比有向图,有4种边)
割边只能是树边。为什么不能是非树边(返祖边)?
因为dfs生成树已经是连通的,删除返祖边明显对连通性没影响。
重边明显不可能是割边,割不断啊
实现
下面代码实现了对 无重边 的无向图求割边,其中,当 isbridge[v] 为真时,(father[v],v) 为一条割边。
想一想为啥记录v点就可以?
答案: 因为v的father是唯一的。 但一个father可以对应多个son
有时我们会用一个pair直接存储bridge的两边。好像更方便
int low[MAXN], dfn[MAXN], idx;
bool isbridge[MAXN];
vector<int> G[MAXN];
int cnt_bridge;
int father[MAXN];
void tarjan(int u, int fa) {
father[u] = fa;
low[u] = dfn[u] = ++idx;
for (const auto &v : G[u]) {
if (!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) {
isbridge[v] = true;
++cnt_bridge;
}
} else if (v != fa) {
low[u] = min(low[u], dfn[v]);
}
}
}
上述代码在有重边的无向图上是有问题的。
参考oiwiki可以增加一个flag 判断是否已有一条边抵达父节点。第一次遇到,就跳过。后续遇到,就要算做重边,当做正常的返祖边来计算。
https://oi-wiki.org/graph/cut/#割边有重边时
int low[MAXN], dfn[MAXN], idx;
bool isbridge[MAXN];
vector<int> G[MAXN];
int cnt_bridge;
int father[MAXN];
void tarjan(int u, int fa) {
bool flag = false;
father[u] = fa;
low[u] = dfn[u] = ++idx;
for (const auto &v : G[u]) {
if (!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) {
isbridge[v] = true;
++cnt_bridge;
}
} else {
if (v != fa || flag)
low[u] = min(low[u], dfn[v]);
else
flag = true;
}
}
}

浙公网安备 33010602011771号