问题
用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是源点s,vn是汇点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)表示节点vi到vj的边ei,j的容量,cf(i,j)表示边ei,j的剩余容量,逆向指针from(j)=i表示BFS搜索中从节点vi搜索到邻节点vj(或者说节点vj是从节点vi来的)。按照以下步骤进行BFS搜索增广路径:
(1) 初始时设置空队列queue,设置任意节点vi的from(i)=nil(表示BFS搜索未开始),最大流flowmax=0,所有边的容量与其剩余容量相等c(i,j)=cf(i,j),边上的流为f(i,j)=f(j,i)=0,将源点s加入队列中并染红;
(2) 当queue不为空时,从中取出头节点vi,若vi=t则已经找到一条增广路径;若vi=t则遍历其所有邻节点找出所有的未被染红且剩余容量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:
上图中的红线是BFS搜索剩余网络中节点的顺序,蓝线是从汇点沿着逆向指针回到源点的路径。
上图是本次BFS搜索的逆向指针。可得增广路径为[0,1,7,8],其中边e0,1=3是剩余容量最小的边,此条增广路径可用的流为3。
然后对该增广路径上的所有边更新剩余容量,下图中每条边上的数字x/y表示边上的流为x,边的容量为y,剩余容量为y−x,其中标记为红色的边的剩余容量为0:
可以发现,每次找出一条增广路径后,剩余网络中至少有一条边的剩余容量变为0,上图中边e0,1的剩余容量cf(0,1)=0。
重复进行BFS搜索寻找增广路径,直到无法找出更多的增广路径时,算法结束。如下图所示:
该算法时间复杂度为O(∣V∣⋅∣E∣2)。
Introduction To Algorithms
源码
EdmondsKarp.h
EdmondsKarp.cpp
测试
EdmondsKarpTest.cpp