最大流问题是求解图上从源点流向汇点的最大流量的问题。
求解最大流问题主要有两种算法:Edmonds-Karp 动能算法(EK 算法)和 Dinic 算法,其中后者在算法竞赛中更为常用。
#基本概念
#流网络
流网络 (Flow Network) 是一个有向图,图中每条边 有一个非负的 容量值 。而且,如果边集合 包含一条边 ,则图中不存在反方向的边 。为了方便起见,如果 ,则定义 。
在流网络的所有节点中,有两个特殊的点:源点 和汇点 。
#流
设 定义在二元组 上的实数函数且满足
- 容量限制(Capacity Constraints):对于每条边,流经该边的流量不得超过该边的容量,即 ;
- 流量守恒(Flow Conservation):从源点流出的流量等于汇点流入的流量,即 ;
那么 称为网络 的流函数。
对于 , 称为边的 流量, 称为边的 剩余容量(Residual Capacity),可以记作 。整个网络的流量为 ,即从源点发出的所有流量之和。为了方便起见,如果 ,则定义 。
一般而言也可以把网络流理解为整个图的流量。而这个流量必满足上述两个性质。
流函数的完整定义如下:
#残量网络
对于流函数 ,残量网络 (Residual Network)是网络 中所有节点和剩余容量大于 的边构成的子图,即
注意,剩余容量大于 的边可能不在原图 中(根据容量、剩余容量的定义以及流函数的斜对称性得到)。可以理解为,残量网络中包括了那些还剩了流量空间的边构成的图,也包括虚边(即反向边)。
#增广路
在原图 中若存在一条从源点到汇点的路径上所有边的剩余容量都大于 ,则这条路径被称为增广路(Augmenting Path)。
#Edmonds-Karp 算法
Edmonds-Karp 算法的基本思路很简单:不断地使用 BFS 去寻找增广路,直到网络上不存在增广路为止。
在每轮寻找增广路的过程中,Edmonds-Karp 算法只考虑所有 的边,用 BFS 找到任意一条从 到 的路径,同时计算出路径上各边的剩余容量的最小值 ,则网络的流量就可以增加 。
需要注意的是,当一条边的流量 时,根据斜对称性质,它的反向边流量 ,此时必定有 。故 Edmonds-Karp 算法在 BFS 时除了原图的边集 外,还应该考虑遍历 中每条边的反向边。
在实现时,只需要维护残量网络即可。当一条边 流过大小为 的流时,令 的剩余容量减小 , 的剩余流量增大 即可。
Edmonds-Karp 算法的时间复杂度为 。然而在实际运用中远远达不到这个上界,效率较高,可以处理 规模的网络。
来自 GitHub Copilot 的补全(未验证):然而在实际应用中,这个算法的时间复杂度可以降低到 ,因为在每轮 BFS 时,只需要更新 中的边的剩余容量,而不需要更新 中的节点。
#代码
1 |
|
#Dinic 算法
Edmonds-Karp 算法每轮可能会遍历整个残量网络,但只找出一条增广路,还有进一步优化的空间。
Dinic 算法不断重复以下步骤,直到在残量网络中 不能到达 :
- 在残量网络上 BFS 求出节点的层次,构造分层图。
- 在分层图上 DFS 求出增广路,在回溯时实时更新剩余容量。另外,每个点可以流向多条出边,同时还加入了若干剪枝(参考程序注释)。
Dinic 算法的时间复杂度为 。但在实际中远远达不到这个上界,一般能够处理 规模的网络,特别地,在求解稠密图上的最大流问题是效率要比前文提到的 Edmonds-Karp 算法更高。
Dinic 算法中的两个优化:
- 多路增广:每找到一条增广路时,若还有残余流量存在,那么可以再找出其他的增广路来利用这些残余流量。这样就可以在一次 DFS 中找出多条增广路,大大提高了算法的效率。
- 当前弧优化:如果一条边已经被增广过,那么该边就没有可能被增广第二次。那么,当下一次进行增广的时候,就可以不必再走那些已经被增广过的边。
#代码
1 |
|
#参考资料
- 0x6A 网络流初步,《算法竞赛进阶指南》(ISBN 978-7-83009-313-6,河南电子音像出版社),李煜东,2019 年 5 月第 5 次修订版。
- 第 26 章 最大流,《算法导论》中译本(ISBN 978-7-111-40701-0,机械工业出版社),2013 年 1 月第三版。
- 1.1.1 网络流的基本概念,AcWing 算法进阶课,闫学灿,2020 年 7 月 25 日。
- 1.1.2 最大流,AcWing 算法进阶课,闫学灿,2020 年 7 月 31 日 ~ 2020 年 8 月 8 日。
- 网络流简介,图论,OI Wiki,2021 年 7 月 11 日。