问题
用压入与重标记算法求网络G=<V,E>的最大流,G是单源点、单汇点,边的容量都为正整数的网络。
定义
设网络中每个节点都有一个水位高度level,当cf(i,j)=c(i,j)−f(i,j)>0时边ei,j仍然可以容纳更多的流,当cf(i,j)=0时称边ei,j为饱和边,不能容纳更多的流。
设节点vi(vi∈V\{s,t})的流入和流出之差为:
x(i)=inflowi−outflowi=u∈V∑f(u,i)−v∈V∑f(i,v) 若相邻节点vi,vj满足cf(i,j)>0,称vi,vj之间可以容纳额外的流。
压入操作
压入操作条件:
(1) 相邻节点vi,vj的水位满足level(i)=level(j)+1(称vj在vi的低位,vi在vj的高位);
(2) 相邻节点vi,vj的边的剩余容量满足cf(i,j)>0;
压入操作:像高处的水流向最低洼的位置,对于满足压入操作条件的相邻节点,由节点vi流向节点vj,边ei,j的剩余容量更新为:
⎩⎨⎧f(i,j)=f(i,j)+Δf(j,i)=f(j,i)−Δx(i)=x(i)+Δx(j)=x(j)−Δ 其中Δ=min(x(i),cf(i,j))。任意节点vi能够流出的最大值为x(i)(不能凭空制造流,每个节点必须有流入才能流出),而边ei,j能够额外容纳的流为cf(i,j),因此实际可用的流是两者的最小值。
网络中将源点视作入流无穷大的节点,即有
inflows=+∞x(s)=+∞ 将汇点视作出流无穷大的节点,即有
outflowt=−∞x(t)=−∞ 重标记操作
重标记操作是调整相邻节点之间的水位高度差的辅助操作,目的是尽可能将更多的流压入汇点。
重标记操作条件:
(1) 节点vi的流入和流出之差满足x(i)>0,说明该节点仍然能够制造出流;
(2) 节点vi存在可以容纳额外的流的邻节点vj(即cf(i,j)>0),且水位高度之差满足level(i)≤level(j);
重标记操作:
level(i)=min{level(j)}+1 其中vj是所有满足重标记条件的vi的邻节点,将vi的水位设置为所有节点中最低的水位加1。
解法
初始时设网络中任意两点间的流为0,即f(i,j)=f(j,i)=0(其中vi,vj为相邻节点),可知任意节点vi的流入流出差为:
x(i)=⎩⎨⎧+∞−∞0vi=svi=tvi∈V\{s,t} 对源点s进行预压入操作(无视水位):
x(i)=f(s,i)=c(s,i) 其中vi是所有与源点s相邻,且满足剩余容量cf(s,i)>0的邻节点。
然后设置网络中节点的水位:
level(i)={∣V∣0vi=svi∈V\{s} 遍历网络找到满足压入操作、重标记操作的相邻节点和边,并进行对应操作。重复这两种操作直到无法继续,算法结束。网络的最大流即为汇点t的邻节点的出流之和:
flowmax=u∈V∑f(u,t) 该算法的时间复杂度为O(∣V∣2⋅∣E∣)。
Introduction To Algorithms
源码
PushRelabel.h
PushRelabel.cpp
测试
PushRelabelTest.cpp