最大流 算法摘记

来源:互联网 发布:linux 翻页查看日志 编辑:程序博客网 时间:2024/05/22 18:41


源自网络与书籍   自己学习 算法摘记


一,概念

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(VE2)
      (代码参考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;

http://blog.csdn.net/u012605629/article/details/38685001

0 0
原创粉丝点击