EdmondsKarp EdmondsKarp算法(最短路径增广算法)

问题

用Edmond Karp算法求网络G=<V,E>G = <V,E>的最大流,GG是单源点、单汇点,边的容量都为正整数的网络。

Ford–Fulkerson方法

Ford-Fulkerson方法是用于求解最大流的方法(并非算法),它通过寻找增广路径(Argumenting Path)来求最大流,但具体寻找的方法有多种算法实现。

网络流中边eu,ve_{u,v}的剩余容量(Residual Capacity)是:

cf(u,v)=c(u,v)f(u,v)c_f (u,v) = c(u,v) - f(u,v)

边的剩余容量定义了剩余网络(Residual Network)Gf=<V,Ef>G_f = <V, E_f>,表示该网络的可用容量。

网络中的增广路径是剩余网络中的一条路径p=[v1,v2,,vn]p = [v_1, v_2, \dots, v_n],其中v1v_1是源点ssvnv_n是汇点tt,且其中每条边ei,je_{i,j}(两端点为vi,vjv_i, v_j)的剩余容量都满足cf(i,j)>0c_f(i,j) \gt 0,其中i,j[1,n]i, j \in [1, n]

Ford-Fulkerson方法的主要过程如下:

(1)(1) 初始时将网络GG看作一个未被使用的原始剩余网络,该网络的最大流初始化为flowmax=0flow_{max} = 0

(2)(2) 尝试从当前剩余网络中找到一条增广路径,该路径经过的所有边的最小的剩余容量Δ=min{c(i,j)f(i,j)}\Delta = min \{ c(i,j) - f(i,j) \}即为这条流可用的容量(类似木桶短板原理)。这条增广路径使最大流的值增大为

flowmax=flowmax+Δflow_{max} = flow_{max} + \Delta

更新该路径上每条边ei,je_{i,j}的剩余容量(满足反对称性)

f(i,j)=f(i,j)+Δf(j,i)=f(j,i)Δcf(i,j)=cf(i,j)Δcf(j,i)=cf(j,i)+Δ\begin{matrix} f(i,j) = f(i,j) + \Delta \\ f(j,i) = f(j,i) - \Delta \\ c_f(i,j) = c_f(i,j) - \Delta \\ c_f(j,i) = c_f(j,i) + \Delta \end{matrix}

(3)(3) 重复第(2)(2)步直到无法找出更多的增广路径,算法结束。flowmaxflow_{max}为该网络的最大流;

Edmonds-Karp算法

Edmonds-Karp算法是Ford-Fulkerson方法的一种经典实现。通过BFS算法找出一条增广路径从源点ss到达汇点tt

c(i,j)c(i,j)表示节点viv_ivjv_j的边ei,je_{i,j}的容量,cf(i,j)c_f(i,j)表示边ei,je_{i,j}的剩余容量,逆向指针from(j)=ifrom(j) = i表示BFS搜索中从节点viv_i搜索到邻节点vjv_j(或者说节点vjv_j是从节点viv_i来的)。按照以下步骤进行BFS搜索增广路径:

(1)(1) 初始时设置空队列queuequeue,设置任意节点viv_ifrom(i)=nilfrom(i) = nil(表示BFS搜索未开始),最大流flowmax=0flow_{max} = 0,所有边的容量与其剩余容量相等c(i,j)=cf(i,j)c(i,j) = c_f(i,j),边上的流为f(i,j)=f(j,i)=0f(i,j) = f(j,i) = 0,将源点ss加入队列中并染红;

(2)(2)queuequeue不为空时,从中取出头节点viv_i,若vi=tv_i = t则已经找到一条增广路径;若vitv_i \neq t则遍历其所有邻节点找出所有的未被染红且剩余容量cf(i,j)>0c_f(i,j) \gt 0的邻节点vjv_j(在剩余网络中进行BFS搜索),将其加入队列queuequeue中,染红,并设置逆向指针from(j)=ifrom(j) = i。这样重复,若最终搜索到汇点tt则找到一条增广路径,沿着逆向指针可以得到该增广路径上的所有边;若直到队列queuequeue为空也没有搜索到汇点tt则说明无法再找到更多的增广路径;

(3)(3) 重复第(2)(2)步,每找到一条增广路径,该路径中边的最小剩余容量Δ=min{c(i,j)f(i,j)}\Delta = min \{ c(i,j) - f(i,j) \}即为该增广路径可用的流(Dinic算法中称为阻塞流BlockingFlowBlocking Flow,即路径中的瓶颈)。更新该路径上所有边的剩余容量:

f(i,j)=f(i,j)+Δf(j,i)=f(j,i)Δcf(i,j)=cf(i,j)Δcf(j,i)=cf(j,i)+Δ\begin{matrix} f(i,j) = f(i,j) + \Delta \\ f(j,i) = f(j,i) - \Delta \\ c_f(i,j) = c_f(i,j) - \Delta \\ c_f(j,i) = c_f(j,i) + \Delta \end{matrix}

更新最大流

flowmax=flowmax+Δflow_{max} = flow_{max} + \Delta

当无法找出更多增广路径时算法结束,flowmaxflow_{max}即为该网络的最大流;

下图演示了一条增广路径的搜索过程,其中源点为00汇点为88

上图中的红线是BFS搜索剩余网络中节点的顺序,蓝线是从汇点沿着逆向指针回到源点的路径。

上图是本次BFS搜索的逆向指针。可得增广路径为[0,1,7,8][0, 1, 7, 8],其中边e0,1=3e_{0,1} = 3是剩余容量最小的边,此条增广路径可用的流为33

然后对该增广路径上的所有边更新剩余容量,下图中每条边上的数字x/yx / y表示边上的流为xx,边的容量为yy,剩余容量为yxy - x,其中标记为红色的边的剩余容量为00

可以发现,每次找出一条增广路径后,剩余网络中至少有一条边的剩余容量变为00,上图中边e0,1e_{0,1}的剩余容量cf(0,1)=0c_f(0,1) = 0

重复进行BFS搜索寻找增广路径,直到无法找出更多的增广路径时,算法结束。如下图所示:

该算法时间复杂度为O(VE2)O(\lvert V \rvert \cdot \lvert E \rvert ^2)

Introduction To Algorithms

源码

EdmondsKarp.h

EdmondsKarp.cpp

测试

EdmondsKarpTest.cpp

Last updated