最近碰到一道题目,求一个图的全局最小割,可惜图论博主学的不太好,至今只记得一个求 s-t 最大流/最小割的 ford-fulkerson。想了想总不能做次最大流吧,最终还是求助了维基百科 🤣
Stoer-Wagner Algorithm
Stoer-Wagner 算法是一个求带非负权无向图中全局最小割的算法,它是在 1995 年由 Mechthild Stoer 和 Frank Wagner 提出的。
算法的核心思想是通过不断的合并某个 s-t 最小割的顶点来缩小图的规模,直到图里只剩下两个合并剩下的顶点。
算法流程
在图 G 中,假设 G 的全局最小割为 C = {S, T},那么对于任何一对 G 上的顶点 (s, t) 来说
- 要么 s 和 t分属S 和 T
- 要么 s 和 t同属S 或 T
Stoer-Wagner 首先找到一个 s-t 最小割,然后将 s 和 t 合并:
- 删除 s 和 t 之间的边
- 对于任何和 s、 t 相邻的顶点 v,与新顶点链接的权重为 w(v, s) + w(v, t)(假设不相邻为 0 权重)
显然,对于任何 s、 t 在同一个集合的割,合并 s、 t 并不影响割的权重。
上述流程(找到一个最小割、合并)为一个阶段,在进行 |V| - 1 次这样的阶段之后,G 中只剩下两个点,那么全局最小割一定为每个阶段的 s-t 最小割以及最后两个点的割中的最小值,如此算法即完成了。
同学们一定发现了,如何找到一个 s-t 最小割才是算法能够高效执行的关键,Stoer-Wagner 算法的巧妙之处就在于此。
因为算法对于 s-t 最小割的起点和终点没有任何要求,所以找到任何一个最小割就行,过程如下:
- 图 G 上任意一个顶点,放入集合中
- 选取一个中的点,使得最大,将它放入中;其中
- 重复执行 步骤 2,直到
- 假设最后加入的两个顶点是和, 合并它们
上述过程中 是一个 s-t 最小割。
正确性证明
要证明算法的正确性,只需要证明阶段中找到的一定是一个 s-t 最小割。
符号定义
- 图
- , 是最后加入集合的两个顶点
- 令为任意一个 s-t 割,不失一般性,令
- 为在顶点加入之前的集合
- 是在由顶点构成的的子图上,由割导出的割
所以,我们有,即只需要证明 。
下面我们将归纳证明 ,。
设是中第一个被放入中的顶点,那么由定义,有
假设对于两个连续被放入中、并且同属于的顶点,归纳假设有
首先,我们有
因为优先于被选取,所以,所以上式有
而由于,所以
所以有 ,证毕。
故而我们知道,算法每个阶段都能找到一个 s-t 最小割。
时间复杂度
每次计算最大的的时间为,最后合并的时间为 ,所以每一个阶段时间复杂度为 ;
一共执行 次,算法总计时间复杂度为 。
其中每次选择最大的可以通过堆进行优化,将时间优化到,总计时间复杂度可以降为 。
这里顺便一提,Stoer-Wagner 算法适用的堆需要支持动态 update,常用的堆为斐波那契堆,在 C++ 的标准 stl 里并没有实现,替代方案可以使用 std::multiset。在 boost 中,对 Stoer-Wagner 算法有直接支持。
References
[1] https://en.wikipedia.org/wiki/Stoer%E2%80%93Wagner_algorithm
[2] http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/stoer_wagner_min_cut.html