一种极其好写的非递归式严格最小割树
本文介绍的算法来自:王文涛 2016 年国集论文《浅谈无向图最小割问题的一些算法及应用》。
ChatGPT 5.6 协助了本文的编写。
吐槽
最小割树的洛谷模板的题解区中,大部分题解写的都不是严格的最小割树(Gomory-Hu 树),而是等价流树。这种树虽然满足任意两点
而能构造方案的 Gomory-Hu 树的递归写法实现又过于复杂(需要进行点的收缩)。
好在原论文中给出了一种非递归式的写法,实现简单,但理解起来较为复杂。本文会先直接给出实现,再给出独立于递归式写法的证明。
文末还给出了一组 Hack 数据,用于说明等价流树得到的结果不一定满足 Gomory-Hu 树的严格性质。
一些规定
- 给定图
G=(V,E) ,V=\{0,1,\dots,n\} ,共n+1 个点。 - 一条边
e\in E 的边权记为c(e) 。 - 对于一个边集
S\subseteq E ,定义c(S)=\sum\limits_{e\in S} c(e) 。 - 定义图的一个割为点集的一个划分
(U,V-U) ,这个割的边集为所有满足一端属于U ,另一端属于V-U 的边的集合,记为\delta(U) 。 - 一个割
(U,V-U) 的权是c(\delta(U)) ,记为d(U) ,显然d(U)=d(V-U) 。 - 称割
(U,V-U) 是(u,v) 的一个割,如果u\in U,v\in V-U 。 - 任取一个
(u,v) 的权最小的割,它的边集记为\alpha(u,v) ,这样的割的权为\lambda(u,v) 。 -
Gomory-Hu 树的定义:称一棵树为Gomory-Hu 树,如果对于树上的每条边
(s,t) ,删去这条边后分成的两个连通块(S,V-S) 恰好是一个(s,t) 的最小割。并且(s,t) 的边权就是\lambda(s,t) 。由定义并结合割的一些性质可以得到结论:对于任意两点
(s,t) ,\lambda(s,t) 恰好等于 Gomory-Hu 树上s\to t 的路径上边权的最小值。
对于大多数题解实现的等价流树,其满足上面这个结论但不满足删去
(s,t) 的边之后两个连通块恰好是(s,t) 的一个最小割。故称其为“非严格”的最小割树。
实现
维护两个数组
遍历
-
设
t=fa_s 。 -
求出
(s,t) 的任意一个最小割\delta(S) ,s\in S,t\in V-S ,将val_s\leftarrow \lambda(s,t) 。 -
遍历所有
fa_v=t 的点v (即所有s 的兄弟),若v\in S ,则将fa_v\leftarrow s ,val_v 不变。 -
若
t>0 ,设p=fa_t ,此时若p\in S ,则将fa_t\leftarrow s ,fa_s\leftarrow p ,并交换val_s,val_t 。
整个过程结束后,对于
我们声称这样建出来的树就是一棵 Gomory-Hu 树。整个流程时间复杂度
:::info[核心代码]
为了方便,实现中令
采用 dinic 算法实现了最小割,其中
for (int s = 1; s <= n; s++) {
int t = f[s];
val[s] = mincut(s, t);
for (int j = 1; j <= n; j++)
if (j != s && f[j] == f[s] && ~dis[j])
f[j] = s;
int p = f[t];
if (~dis[p]) {
f[t] = s, f[s] = p;
swap(val[s], val[t]);
}
}
:::
证明
一些重要引理&定理
引理 1:对于任意不同的三点
u,v,w ,\lambda(u,w)\ge \min(\lambda(u,v),\lambda(v,w)) 。
证明:随便取一个
推论 1:对于任意不同的两点
u,v ,有\lambda(u,v)\ge\min(\lambda(u,w_1),\lambda(w_1,w_2),\dots,\lambda(w_k,v)) 。
引理 2:对于任意
A,B\subseteq V ,d(A)+d(B)\ge d(A\cup B)+d(A\cap B) ,即函数d 的子模性。
证明:按顶点是否属于
:::info[更容易的理解方式] 画出论文中类似的图: :::
引理 3:对于任意
A,B\subseteq V ,d(A)+d(B)\ge d(A\backslash B)+d(B\backslash A) 。其中A \backslash B 表示\{x|x\in A\land x\notin B\} ,即A\cap V-B 。
证明:对
定理 4(uncrossing):对于两点
s,t 的一个最小割\alpha(s,t) ,设其s 的一侧为W ,则对于所有不同的u,v\in W ,存在(u,v) 的一个最小割\delta(Y) ,使得Y\subseteq W 。
证明:设
-
 对 $W$ 和 $X$ 使用**引理 2**,得到: $$d(W)+d(X)\ge d(W\cup X)+d(W\cap X)$$ 并且: - $W\cup X$ 是 $(s,t)$ 的割,所以 $d(W)\le d(W\cup X)$。 - $W\cap X$ 是 $(u,v)$ 的割,所以 $d(X)\le d(W\cap X)$。 综上 $d(W)=d(W\cup X)$,$d(X)=d(W\cap X)$。 所以令 $Y$ 为 $W\cap X$ 即可满足条件。 -
这个 uncrossing 是接下来证明中非常重要的一个工具。
做法拆解
我们在维护什么?
假设目前处理完
处理完
:::info[回顾我们的做法]
遍历
-
设
t=fa_s 。 -
求出
(s,t) 的任意一个最小割\delta(S) ,s\in S,t\in V-S ,将val_s\leftarrow \lambda(s,t) 。 -
遍历所有
fa_v=t 的点v (即所有s 的兄弟),若v\in S ,则将fa_v\leftarrow s ,val_v 不变。 -
若
t>0 ,设p=fa_t ,此时若p\in S ,则将fa_t\leftarrow s ,fa_s\leftarrow p ,并交换val_s,val_t 。
整个过程结束后,对于
我们需要在处理
-
为什么能把
s 的一个兄弟v 的子树整棵接到s 下面,并且val_v 还不用变? -
为什么
s 的父亲的父亲p 在s 一侧时,可以把s “转”到t 的上方,并交换val_s,val_t ?
对于兄弟
首先对于那些
对于
情况 1: v\notin S
类似 uncrossing 的证法,可以证明
情况 2:v\in S
同样地,我们可以把
接下来还有一个问题,为什么此时
根据引理 1,
因为
又因为
综上,
对于父亲
设
情况 1:p\notin S
和刚才的
情况 2:p\in S
可以把
这时候就可以让
p
|
t
/ | \
not-S s not-S
/ \
S S
变成
p
|
s
/ | \
S S t
/ \
not-S not-S
对于边权:
由于
所以只需要证明
和刚刚证明边权相等的部分一样,根据引理 1,
因为
又因为
综上,
于是,整个做法的正确性得到了证明。
Hack
以题解区 @_LHF_ 的代码为例,给出如下数据:
2 3
0 1 1
1 2 2
2 0 2
代码建出来的树是:
0-----1-----2
3 3
但对于删除
事实上这张图的唯一一种 Gomory-Hu 树应该形如:
0-----2-----1
3 3
这个 Hack 仅仅是针对于这份代码的写法。实际上在大多数题解实现的等价流树算法中,每次递归选取的两点不同,最后建出来的树也会不同。但只需改变这个 Hack 中节点的编号顺序,大概率仍能起到效果。
感谢大家百忙之中阅读这篇文章。