最大流

来源:互联网 发布:视频剪刀手软件 编辑:程序博客网 时间:2024/05/22 14:49

最近学习最大流的问题。

感觉一个博客写的还是不错的,推荐给大家。

http://blog.csdn.net/y990041769/article/details/21026445

求网络流有很多算法,这几天学习了两种,记录一下EK算法。

首先是网络流中的一些定义:

V表示整个图中的所有结点的集合.
E表示整个图中所有边的集合.
G = (V,E) ,表示整个图.
s表示网络的源点,t表示网络的汇点.
对于每条边(u,v),有一个容量c(u,v)   (c(u,v)>=0),如果c(u,v)=0,则表示(u,v)不存在在网络中。相反,如果原网络中不存在边(u,v),则令c(u,v)=0.
对于每条边(u,v),有一个流量f(u,v).

一个简单的例子.网络可以被想象成一些输水的管道.括号内右边的数字表示管道的容量c,左边的数字表示这条管道的当前流量f.


网络流的三个性质:

1、容量限制:  f[u,v]<=c[u,v]
2、反对称性:f[u,v] = - f[v,u]
3、流量平衡:  对于不是源点也不是汇点的任意结点,流入该结点的流量和等于流出该结点的流量和。
只要满足这三个性质,就是一个合法的网络流.

最大流问题,就是求在满足网络流性质的情况下,源点 s 到汇点 t 的最大流量。


求一个网络流的最大流有很多算法 这里首先介绍 增广路算法(EK)

学习算法之前首先看了解这个算法中涉及到的几个图中的定义:


**残量网络

为了更方便算法的实现,一般根据原网络定义一个残量网络。其中r(u,v)为残量网络的容量。
r(u,v) = c(u,v) – f(u,v)
通俗地讲:就是对于某一条边(也称弧),还能再有多少流量经过。
Gf
 残量网络,Ef 表示残量网络的边集.


这是上面图的一个残量网络。残量网络(如果网络中一条边的容量为0,则认为这条边不在残量网络中。

r(s,v1)=0,所以就不画出来了。另外举个例子:r(v1,s) = c(v1,s) – f(v1,s) = 0 – (-f(s,v1)) = f(s,v1) = 4.

其中像(v1,s)这样的边称为后向弧,它表示从v1到s还可以增加4单位的流量。

但是从v1到s不是和原网络中的弧的方向相反吗?显然“从v1到s还可以增加4单位流量”这条信息毫无意义。那么,有必要建立这些后向弧吗?

显然,第1个图中的画出来的不是一个最大流。

但是,如果我们把s -> v2 -> v1 -> t这条路径经过的弧的流量都增加2,就得到了该网络的最大流。

注意到这条路径经过了一条后向弧:(v2,v1)。

如果不设立后向弧,算法就不能发现这条路径。

**从本质上说,后向弧为算法纠正自己所犯的错误提供了可能性,它允许算法取消先前的错误的行为(让2单位的流从v1流到v2)

注意,后向弧只是概念上的,在程序中后向弧与前向弧并无区别.


**增广路

增广路定义:在残量网络中的一条从s通往t的路径,其中任意一条弧(u,v),都有r[u,v]>0。


如图绿色的即为一条增广路。

看了这么多概念相信大家对增广路算法已经有大概的思路了吧。


**增广路算法

增广路算法:每次用BFS找一条最短的增广路径,然后沿着这条路径修改流量值(实际修改的是残量网络的边权)。当没有增广路时,算法停止,此时的流就是最大流。


**增广路算法的效率

设n = |V|,  m = |E|

每次增广都是一次BFS,效率为O(m),而在最坏的情况下需要(n-2增广。(即除源点和汇点外其他点都没有连通,所有点都只和s与t连通)

所以,总共的时间复杂度为O(m*n),所以在稀疏图中效率还是比较高的。


hdoj 1532是一道可以作为模板题目练手。

Drainage Ditches

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 15978    Accepted Submission(s): 7592


Problem 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 41 2 401 4 202 4 202 3 303 4 10
 

Sample Output
50
 
主要内容是
输入m n,   m是边数,n是点数。 
接下来m行:   起点,终点,最大流量。
求以 1 为源点, n为汇点的最大流。


模板代码:

#include <cstring>#include <cstdio>#include <iostream>#include <vector>#include <algorithm>using namespace std;const int N = 1100;const int inf = 0x3f3f3f3f;struct node{    int to;    int cap;    int rev;};vector<node> v[N];bool used[N];void AddNode(int from, int to, int cap){    node temp;    temp.to = to;    temp.cap = cap;    temp.rev = v[to].size();    v[from].push_back(temp);    temp.to = from;    temp.cap = 0;    temp.rev = v[from].size()-1;    v[to].push_back(temp);}int dfs(int s, int t, int f){    int i;    if ( s == t )        return f;    used[s] = true;    for ( i = 0;i < v[s].size(); i++ )    {        node &temp = v[s][i];        if ( used[temp.to] == false&&temp.cap > 0 )        {            int d = dfs(temp.to, t, min(f, temp.cap));            if ( d > 0 )            {                temp.cap = temp.cap-d;                v[temp.to][temp.rev].cap = v[temp.to][temp.rev].cap+d;                return d;            }        }    }    return 0;}int maxFlow(int s, int t){    int flow = 0;    while ( true )    {        memset (used, false, sizeof(used));        int temp = dfs(s, t, inf);        if ( temp == 0 )            return flow;        flow = temp+flow;    }}int main(){    int x, y, z;    int n, m, i;    while ( ~scanf ( "%d %d", &n, &m ) )    {        memset ( v, 0, sizeof(v) );        for ( i = 0;i < n; i++ )        {            scanf ( "%d %d %d", &x, &y, &z );            AddNode(x, y, z);        }        printf ( "%d\n", maxFlow(1, m) );    }    return 0;}

代码菜鸟,如有错误,请多包涵!!!

如有帮助记得支持我一下,谢谢!!!

0 0
原创粉丝点击