求解最大流的高效算法 —— Dinic 算法

1. Dinic 算法的优化



Dinic 算法和 Ford-Fulkerson 算法的基本想法是一样的,寻找增广链 → 增加流量。不过直接这样做会慢的原因是,每次需要不断增广,可能会有浪费。Dinic 算法的优化思想是,一次性尽量增广多条路径,显然会加快速度。


接下来讲讲具体的实现。我们先用 BFS 遍历所有的点,目的是记录下每个节点的深度,即从 s 到每个节点的距离。(这个数组之后会有用处)注意这个过程中,已满流的边无需访问。


然后是一遍 DFS,也是从 s 出发。我们不走 " 同级 " 的,即深度必须是递增的序列(用到之前的数组),否则会走 " 回头路 "(会慢)。对于一个节点,需要将其上级分配过来的流量,分配给下级,注意不能超过下级的容量。如果给了下级流量,却没有用,说明下次无需访问这个节点了。这样每走到 t,就相当于找到一条增广链了,可以退回去接着找。


重复以上操作(一遍 BFS+DFS),即可求出最大流。


2. Dinic 算法的举例实现


扫描二维码关注公众号,回复: 13129962 查看本文章

我们来举一个例子吧,下面是一个比较经典的图(上次也举过)。



我们先用 BFS 标好深度,然后开始 DFS。这样操作一次之后,得到的图为(并不唯一):




此时的图中,已找不到增广链了,即求得的最大流为 4。之前的 Ford-Fulkerson 算法,至少需要 2 次才能完成,Dinic 算法显然是更快了。



3. 示例代码


下面是我写的 Dinic 算法的代码,仅供参考。


其中 s 和 t 表示源点和汇点的编号,d 是记录深度的数组。图的存储方式、部分函数的命名等说明,可以参考算法笔记——求解最大流的 Ford-Fulkerson 算法




4. 复杂度分析


Dinic 算法具体的时间复杂度如何呢?每次跑一遍 BFS,一遍 DFS,在最坏情况下,时间复杂度为 O ( n × n × m )。由于一般的图边数 m 都是不小于 n 的,所以一个 × m,一个 × n,Dinic 算法比起 Ford-Fulkson 算法来说,还是很快的。


5. 后记


又到了八卦的时间啦,我来介绍一下 Dinic 算法的历史吧。本来的发明者是俄罗斯(当时的苏联)的 Dinitz,当时还是个大学生。Adelson-Velsky 是他的导师,在课上布置了网络流相关的一个作业。后来 Dinitz 自己想出了现在的这个 Dinic 算法,并与 1969 年发表了。


补充一句,Adelson-Velsky 教授其实是 AVL树 的发明人,即平衡树,有兴趣的同学可以自己研究一下,我以后可能会介绍哦。


1974年,一位来自以色列海法的数学家 Shimon Even 发现了这个算法,经过优化后,介绍到了西方。他注明了这个算法不是自己发明的,而应当归功于 Dintz。但是由于他不会念俄文,就写成了 Dinic。Shimon Even 以前曾在哈佛读书,导师是曾经就读于中国清华大学的王浩教授,是著名的现代数理逻辑之父。

猜你喜欢

转载自blog.csdn.net/jwg2732/article/details/78516817