跟我一起学算法——最大流
@
定义
最大流(Maximum Flow)
流网络((flownetwork))
在有向图 G 中,流是一实函数 f:V×VR,并满足以下三个条件:
容量限制 :对于所有的 u,v∈V,f(u,v)≤c(u,v)
反对称性 :对于所有的 u,v∈V,f(u,v)= -f(v,u)
流守恒 (流进=流出):图中每条边(u,v)∈E 均为非负 容量 c(u,v)≥0。如果(u,v)不
属于E,则 c(u,v)=0。
源s,汇t
某个顶点的 总净流 定义为:净流=流出总正流-流入总正流
多源多汇
加入s和t就可变成单源单汇
剩余网络(residual network)
剩余网络就是在流网络中除去某个流后, 所有剩余容量(residual capacity)组成的网络。
剩余流量:二个顶点u,v间的剩余容量定义为:c_f(u,v)=c(u,v)-f(u,v)
对于给定的流网络G=(V,E)以及流f,则G_f(V,E_f) 是相对与流f的剩余网络。
增广路径((Augmenting Path)
从s到t的简单路径p。
c_f(p) = min(c_f(u,v) ; (u,v) ∈ p) , 即增广路径的最大流量由p中边的最小容量决定。
令f是流网络G=(V,E)的一个流,令P是剩余网络Gf的一 条增广路径。定义函数f_p:V×V->R,则
f_p是G_f的一个流且流值为 |f_p|=c_f(P)>0
定义函数f’:V×V->R且f’=f+fp,那么f’ 是G中的一个流,其流值|f’|=|f|+|f_p|>|f|。
截(Cut)
流网络的截(S,T)是顶点V的一种划分,其中T=V-S, s∈S,t∈T。
流函数f(S,T):穿越截(S,T)的净流,即流出总正流- 流入总正流。
C(S,T):截(S,T)的容量,即从S到T的容量之和。
最小截:所有截中容量最小的截。
任意截(S,T)的净流f(S,T)=|f|。
流网络G中的任何流值均受限于G中截的容量限制, f(S,T)<=c(S,T)
最大流最小截定理:如果f是源为s汇为t的流网络G中的一个流,那么以下条件相等:f是G中的最大流<=>
剩余网络没有增广路径 <=> G中存在截(S,T),使|f|=C(S,T)
参考https://www.jianshu.com/p/beca253fdc9f
Ford-Fulkerson算法
Ford-Fulkerson-Method(G,s,t)
初始化流f=0
while 存在增广路径P
do 沿增广路径P增加流f
根据增加的流,更新边的容量
return f
时间复杂度O(fE) , f为增广路径的数量,可大可小。
Edmonds-Karp算法
Edmonds-Karp 算法是 Ford-Fulkerson 方法的一种具体实现。它采用 BFS 搜索方法在剩余网络
中寻找增广路径。具体做法是先对每条边的权值统一赋值为 1,然后找一条从 s 到 t 的最短
路径。基于此方法,Edmonds-Karp 算法求最大流的时间为 O(VE^2)。
应用:最大二分图匹配(Maximum Bipartite Matching)
-
二分图
把顶点集V划分为二个不相交的子集合L和R,即 V=L∪R,L∩R=Φ,并且只有L和R之间存在边,L、R
内部的顶点间没有边,则称这样的图为二分图。 -
匹配
二分图中具有最多边的匹配称为最大二分图匹配 -
求二分图的最大匹配问题
首先需把二分图转换为流网络:
- 增加一个源s和汇t及s到L中所有顶点的边以及R中所有顶点到t的边
- 把无向图改为有向图,方向为s->L->R->t
- 给所有边赋值为单位容量值
-
二分图G的一个最大匹配M的目数等于其相关流 网络G’的最大流f的流值。
-
算法时间为O(VE)
Push-relable算法
定义
-
预流
V中除了s,t外的v不满足流守恒,若v的净流>=0,称为溢出顶点。 -
高度
h(s)=|V| , h(t)=0 ,保持不变
其他顶点高度初始化为0,h(u) = 0
对于边(u,v),h(u)<=h(v)+1
push
三个条件:
- u为溢出顶点
- h(u)=h(v)+1
- 存在边容量>0,c_f(u,v)>0
Push操作:
向下推的流量d=min(e(u), c_f(u,v)),即取u的净流与边容量的较小值,取后者时称为饱和push。
e(v) += d
e(u) -= d
push后 u,v 之间建立一条反向的容量为d的边,也可以直接抵消正向容量。
relable
两个条件:
- u为溢出顶点
- h(u)<=h(v)
操作:
h(u) = 1 + min(h(v)) , v与u相连的顶点。
初始化(init)
- 高度初始化
- 把s的流以容量为限推到与之相连的各个顶点,e(u)=c(s,u)
算法
push_relanble(G)
init_preflow(G)
while there exists a vertex that can be pushed or relabled
do choose push or relable at will