Appearance
网络最大流
在管道网络、物流系统中,经常需要求解满足各个通路容量流量限制下,能从起点往终点运送多少东西。这就是最大流问题,要回答的限制下,从源头把尽可能多的流送到终点的最大流量和方案。
流与合法流
直观地说,流是一个带权有向图,边的权重就是这条边最多能通过多少流。整张图中有一个特别的起点
形式化地,一个流网络是带权有向图
第一类是容量约束。对任意边
,实际流量不能为负,也不能超过容量: 第二类是流量守恒。对除
以外的任意顶点 ,流入它的总流量等于流出它的总流量,也就是
在这两个条件下,源点
最大流问题的目标,就是在所有合法流中找到一个使
割与瓶颈
在直觉上,一个网络的能量输出往往受最细的那几根管子限制。为了刻画这种“瓶颈”,我们引入割的概念。
可以把割想象成在图上画出一条“切割线”,把
形式化的说,设
割的容量定义为所有从
有一个简单但重要的事实:任意合法流的流量都不会超过任意一个割的容量。因为所有从
最大流最小割定理
最大流最小割定理指出:
在一个流网络中,最大的可行流量等于最小的
割的容量。
换句话说,从上界的角度看,任何一个割都给出了流量的上限;从算法的角度看,最大流算法会不断尝试增加流量,直到再也找不到新的“通路”为止,这时它刚好达到了某个割的容量上界。于是,全图中最紧的那个瓶颈,恰好决定了最大流的大小。
总而言之,流量受全局瓶颈限制,而增广型的算法做的就是一步步把流量顶到这个瓶颈上。
增广路框架:Ford–Fulkerson
求最大流最经典的思路是增广路(augmenting path)。可以这样理解:一开始所有边上流量为 0,此时显然是一个合法流。此后,只要还能在网络中找到一条从
为了描述“还能多送多少”,我们在当前流的基础上构造一张残量网络(residual graph)。对于每条边
在残量网络上,从
这个方法的核心是把“能不能再多送一点流”转化成“还能不能在残量网络里找到一条路”。不同的最大流算法,区别主要在于如何在残量网络中找路径、以及怎样组织多次增广。
这一整套框架通常被统称为 Ford–Fulkerson 方法。用伪代码可以简要写成:
text
初始化所有流量 f(u,v) = 0
while 在残量网络中存在 s 到 t 的路径 P:
找出 P 上所有边的残量最小值 Δ
沿 P 上的边增加流量 Δ
更新正向边与反向边的残量Edmonds–Karp 算法
Edmonds–Karp 是 Ford–Fulkerson 的一个具体实现,它在残量网络中总是用 BFS 找“边数最少”的增广路。也就是说,每次增广都沿着当前残量图中从
算法的框架与前面一样:先在残量图上用 BFS 找一条从
这样做的好处是,BFS 找到的路径长度可以帮助我们控制增广的次数,从而保证整体复杂度。理论上,Edmonds–Karp 的时间复杂度是
整体流程可以概括为:
python
def max_flow_EK():
初始化 f = 0
while True:
用 BFS 在残量网络中找 s 到 t 的路径 P
if 不存在路径:
break
Δ = P 上边的残量最小值
沿 P 更新流量和残量
返回当前流量 |f|Dinic 算法
Dinic 算法可以看作对增广路思想的进一步组织和优化,是竞赛中常用的最大流算法之一。
Dinic 的第一步是构造一张分层图。在当前残量网络中,从源点 dist。然后我们只保留那些满足 dist[v] = dist[u] + 1 的边,得到一张只允许“沿着层次向前走”的新图。如果在这张图里汇点
在分层图上,Dinic 第二步是寻找一个阻塞流。做法是:用 DFS 沿着层次递增的边不断从
算法整体上就是反复执行“构造分层图、在分层图内找到阻塞流”这两个步骤,直到分层图中