最大流问题

最近又复习了下最大流问题,每次看这部分的内容都会有新的收获。可以说最大流问题的资料网上一搜一大把,根本没有必要自己写;但是大部分资料上的专业术语太多了,初学很难理解,至少我当年学这部分的时候前几次就没有看懂。所以我准备备份一点个人的理解。

图-1

 

 

  如图-1所示,在这个运输网络中,源点S和汇点T分别是1,7,各边的容量为C(u,v)。图中红色虚线所示就是一个可行流。标准图示法如图-2所示:


 

 

其中p(u,v) / c(u,v)分别表示该边的实际流量与最大容量。

 

关于最大流

  熟悉了什么是网络流,最大流也就很好理解了。就是对于任意的uV-{s},使得p(s,u)的和达到最大。上面的运输网络中,最大流如图-3所示:MaxFlow=p(1,2)+p(1,3)=2+1=3

  在介绍最大流问题之前,先介绍几个概念:残余网络,增广路径,反向弧,最大流定理以及求最大流的Ford-Fulkerson方法。

残余网络 增广路径 反向弧

  观察下图-4,这种状态下它的残余网络如图-5所示:



   

 

  也许现在你已经知道什么是残余网络了,对于已经找到一条从S T的路径的网络中,只要在这条路径上,把C(u,v)的值更新为C(u,v)-P(u,v),并且添加反向弧C(v,u)。对应的增广路径Path为残留网络上从ST的一条简单路径。图-41247就是一条增广路径,当然还有1347

  此外在未做任何操作之前,原始的有向图也是一个残余网络,它仅仅是未做任何更新而已

 

最大流定理

  如果残留网络上找不到增广路径,则当前流为最大流;反之,如果当前流不为最大流,则一定有增广路径。

 

Ford-Fulkerson方法

  介绍完上面的概念之后,便可以用Ford-Fulkerson方法求最大流了。为什么叫Ford-Fulkerson方法而不是算法,原因在于可以用多种方式实现这一方法,方式并不唯一。下面介绍一种基于广度优先搜索(BFS)来计算增广路径P的算法:Edmonds-Karp算法。

  算法流程如下:

  设队列Q:存储当前未访问的节点,队首节点出队后,成为已检查的标点;

  Path数组:存储当前已访问过的节点的增广路径;

  Flow数组:存储一次BFS遍历之后流的可改进量;

  Repeat:

    Path清空;

    源点S进入PathQPath[S]<-0Flow[S]<-+∞;

    While Q非空 and 汇点T未访问 do

        Begin

            队首顶点u出对;

            For每一条从u出发的弧(u,v) do

                If v未访问 and (u,v) 的流量可改进;

                Then Flow[v]<-min(Flow[u],c[u][v]) and v入队 and Path[v]<-u

    End while

   

    If(汇点T已访问)

    Then 从汇点T沿着Path构造残余网络;

  Until 汇点T未被访问

 

应用实例

  这是一道最大流的入门题,题目如下:

  http://acm.pku.edu.cn/JudgeOnline/problem?id=1273

Description

  Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.

Input

  The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

Output

  For each case, output a single integer, the maximum rate at which water may emptied from the pond.

Sample Input

5 4

1 2 40

1 4 20

2 4 20

2 3 30

3 4 10

Sample Output

50

 1 #include <iostream>
 2 #include <queue>
 3 using namespace std;
 4 
 5 const int N = 210;
 6 const int INF = 0x7FFFFFFF;
 7 int n,m,map[N][N],path[N],flow[N],start,end;
 8 queue<int> q;
 9 
10 int bfs(){
11     int i,t;
12     while(!q.empty()) q.pop();
13     memset(path,-1,sizeof(path));
14     path[start]=0,flow[start]=INF;
15     q.push(start);
16     while(!q.empty()){
17         t=q.front();
18         q.pop();
19         if(t==end) break;
20         for(i=1;i<=m;i++){
21             if(i!=start && path[i]==-1 && map[t][i]){
22                 flow[i]=flow[t]<map[t][i]?flow[t]:map[t][i];
23                 q.push(i);
24                 path[i]=t;
25             }
26         }
27     }
28     if(path[end]==-1return -1;
29     return flow[m];                   //一次遍历之后的流量增量
30 }
31 int Edmonds_Karp(){
32     int max_flow=0,step,now,pre;
33     while((step=bfs())!=-1){          //找不到增路径时退出
34         max_flow+=step;
35         now=end;
36         while(now!=start){
37             pre=path[now];
38             map[pre][now]-=step;      //更新正向边的实际容量
39             map[now][pre]+=step;      //添加反向边
40             now=pre;
41         }
42     }
43     return max_flow;
44 }
45 int main(){
46     int i,u,v,cost;
47     while(scanf("%d %d",&n,&m)!=EOF){
48         memset(map,0,sizeof(map));
49         for(i=0;i<n;i++){
50             scanf("%d %d %d",&u,&v,&cost);
51             map[u][v]+=cost;           //not just only one input
52         }
53         start=1,end=m;
54         printf("%d\n",Edmonds_Karp());
55     }
56     return 0;
57 }
58 

posted on 2009-04-19 20:58 极限定律 阅读(12188) 评论(15)  编辑 收藏 引用 所属分类: ACM/ICPC

评论

# re: 最大流问题[未登录] 2009-05-29 10:46 Wing

嗯, 您的一些文章很有独特的见解, 以后定期过来学习~ O(∩_∩)O哈哈~
希望您再接再厉, 顺便预祝 有道难题, 百度之星 获得好成绩  回复  更多评论   

# re: 最大流问题 2009-08-03 09:57 Leng

很好很详细  回复  更多评论   

# re: 最大流问题 2009-08-13 10:11 va

好东西啊 经常搜到大牛的博客  回复  更多评论   

# re: 最大流问题 2010-04-04 23:46 lyt9469

太好了,深入浅出  回复  更多评论   

# re: 最大流问题 2010-06-10 17:19 ss

4~7的反向边错了吧?  回复  更多评论   

# re: 最大流问题 2010-11-13 10:37 Crazy_Js

不错,写的很好,
顺便问下我在有些书上看到在寻找可增广路径时需要同时寻找包含反向边的可增路径,但我也很迷惑我感觉这没必要,我见你上面的描述也没有搜索含反向边的增广路径,盼指点迷津,谢谢  回复  更多评论   

# re: 最大流问题 2010-11-29 15:47 gdut

比黑书里面讲的好,黑书里面我看不懂  回复  更多评论   

# re: 最大流问题 2010-12-10 10:29 中国人

请问一下, 添加反向边 有什么道理? 虽然我知道程序是正确的,但不知道为什么要添加反向边.请指教
  回复  更多评论   

# re: 最大流问题 2010-12-13 18:41 ACM初学者

收藏了,谢谢了,写的很好  回复  更多评论   

# re: 最大流问题 2010-12-16 18:10 RnMss

这图……是……NOI2006WC的……***~~~@@@  回复  更多评论   

# re: 最大流问题 2011-12-19 00:44 22

错的图  回复  更多评论   

# re: 最大流问题 2011-12-30 20:24 bcydsjbr

1,1吧@ss
  回复  更多评论   

# re: 最大流问题[未登录] 2012-03-03 12:29 bob

反向边是为了给算法一个改正以前错误的途径,自己画画就知道了  回复  更多评论   

# re: 最大流问题 2012-06-24 22:42 ex

讲解很清晰  回复  更多评论   

# re: 最大流问题 2013-10-21 16:47 LittleFIsh

文章很牛逼,不过有一个小小的错误,在图4和图5中,有一个地方相冲突,就是图4中的4和7节点之间的流量,与图5中c和t节点的流量不一致。  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2019年7月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(10)

随笔分类

随笔档案

友情链接

搜索

最新评论

阅读排行榜

评论排行榜