源自网络与书籍 自己学习 算法摘记
一,概念
1)流网络:简单有向图,且有两个特别的顶点(源点s,汇点t)
2)流的边标识为f(u,v)/c(u,v),流量/容量
3)流的三个性质:
对于所有边 流量<容量
反对称性 f(u,v)=-f(v,u)
流守恒性 正向流与反响流之和为零
4)割:流网络G=(V,E)的割(S,T)将顶点V划分为S和T=V-S两部分,
定义割的容量为C(S)割这条线上S中顶点到T中顶点的容量之和
5)残留网络:残留容量 c f (u, v) = c(u, v) - f (u, v)//边的容量减去边的实际流量
6)增广路径:对于残留网络 G f 中的一条 s-t 路径 p 称其为增广路径
二,最大流和最小割问题
1)最大流:对于一个流网络 G (V , E ) ,其流量 f 的最大值称为最大流,最大流问题就
是求一个流网络的最大流。
2)最小割:是指流网络中容量最小的割
如图-1所示,在这个运输网络中,源点S和汇点T分别是1,7,
各边的容量为C(u,v)。图中红色虚线所示就是一个可行流。
其中p(u,v) / c(u,v)分别表示该边的实际流量与最大容量。
所以,最大流就是对于任意的u∈V-{s},使得p(s,u)的和达到最大。
残余网络,增广路径,反向弧,最大流定理以及求最大流的Ford-Fulkerson方法。
观察下图-4,这种状态下它的残余网络如图-5所示:
对于已经找到一条从S 到T的路径的网络中,只要在这条路径上,把C(u,v)的值更新为C(u,v)-P(u,v),
并且添加反向弧C(v,u)。对应的增广路径Path为残留网络上从S到T的一条简单路径。
图-4中1,2,4,7就是一条增广路径,当然还有1,3,4,7。
最大流定理:增广路径与最大流等价
如果残留网络上找不到增广路径,则当前流为最大流;反之,如果当前流不为最大流,则一定有增广路径。
来个例子吧:
三个核心:残留网络、增广路径和流网络的割;
所测试的网络结构图如图所示:
第1次遍历在残留网络中找到S->V2->V1->V3->T这条增广路径(下图A),
找到最小的4:
这时的网络流量如图B
执行第2次遍历的时候在残留网络中找到S->V2->V4->T这条增广路径(下图A),
找到最小的4;
这时的网络流量如图B
执行第3次遍历的时候在残留网络中找到S->V2->V4->V3->T这条增广路径(下图A),
找到最小的5;
这时的网络流量如图B
执行第4次遍历的时候在残留网络中找到S->V1->V2->V4->V3->T这条增广路径(下图A),
找到最小的2;
这时的网络流量如图B
执行第5次遍历的时候在残留网络中找到S->V1->V3->T这条增广路径(下图A),
找到最小的8;
这时的网络流量如图B
执行第6次遍历的时候在残留网络中再找不到增广路径,
箭头向右的连贯的路径没有;
此时找到网络最大流为23(第一个出去的)
Ford-Fulkerson方法
每次找增广路,把这条路上的所有点的流量加上这条路上的残余容量,再找新的增广路,直到找不到为止,它有很多种实现方法,下面给出算法导论上的伪代码
Ford_Fulkerson( G, s, t )
{
for each edge( u, v )∈E[G]
do f[u,v]= 0
f[v,u]= 0
while there exists a path p from s to t in the residual network Gf
do Cf(p)= min{ Cf(u,v) | (u,v) is in p }
for each edge(u,v) in p
do f[u,v]+= Cf(p)
f[v,u]= -f[u,v]
Edmonds-Karp算法
就是用广度优先搜索来实现Ford-Fulkerson方法中对增广路径的计算,时间复杂度为O(VE
2)
(代码参考NOCOW)
#define VMAX 201
int
n, m;
//
分别表示图的边数和顶点数
int
c[VMAX][VMAX];
int
Edmonds_Karp(
int
s,
int
t )
{ //输入源点和汇点
int p, q, queue[VMAX], u, v, pre[VMAX], flow= 0, aug;
while(true){
memset(pre,-1,sizeof(pre)); //记录父节点
for( queue[p=q=0]=s; p<=q; p++ ){ //广度优先搜索
u= queue[p];
for( v=0; v<m&&pre[t]<0; v++ )
if( c[u][v]>0 && pre[v]<0 )
pre[v]=u, queue[++q]=v;
if( pre[t]>=0 ) break;
}
if( pre[t]<0 ) break; //不存在增广路
aug= 0x7fff; //记录最小残留容量
for( u=pre[v=t]; v!=s; v=u,u=pre[u] )
if(c[u][v]<aug) aug=c[u][v];
for( u=pre[v=t]; v!=s; v=u,u=pre[u] )
c[u][v]-=aug, c[v][u]+=aug;
flow+= aug;
}
return flow;
}
来个题目吧:
HDU 1532 Drainage Ditches;