Edmonds Karp - Edmonds Karp算法(最短路径增广算法)


问题

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

Ford–Fulkerson方法

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

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

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

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

网络中的增广路径是剩余网络中的一条路径p=[v1,v2,,vn],其中v1是源点svn是汇点t,且其中每条边ei,j(两端点为vi,vj)的剩余容量都满足cf(i,j)>0,其中i,j[1,n]

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

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

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

flowmax=flowmax+Δ

更新该路径上每条边ei,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)+Δ

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

Edmonds-Karp算法

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

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

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

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

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

f(i,j)=f(i,j)+Δf(j,i)=f(j,i)Δcf(i,j)=cf(i,j)Δcf(j,i)=cf(j,i)+Δ

更新最大流

flowmax=flowmax+Δ

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

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

EdmondsKarp1.png

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

EdmondsKarp2.png

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

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

EdmondsKarp3.png

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

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

EdmondsKarp4.png

该算法时间复杂度为O(|V||E|2)


Introduction To Algorithms


源码

EdmondsKarp.h

EdmondsKarp.cpp

测试

EdmondsKarpTest.cpp