poj1273 网络流 Edmonds_Karp

Drainage Ditches
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 58912 Accepted: 22614

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

网络流陆续搞了好几次,看了好多资料,终于搞明白了。这里先讲一下Ford-Fulkerson,之前被一些资料误导,Ford-Fulkerson写的是Edmonds_Karp算法,当要学习Edmonds_Karp算法时,发现这两个算法怎么没有区别?

后来在看了大量资料从字里行间体会出来,其实Ford-Fulkerson只是一种思想,还称不上算法,思想里包含一个找增广路过程,但没有规定如何找增广路,因此假设最大流为U,而每次增广1点流量,那么需要增广U次,每次增广需要遍历整幅图O(m+n),总复杂度O((m+n)U),当U较大时,这种随意找增广路算法就不可行了。

于是,就有人提出利用BFS来找增广路,就是Edmonds_Karp算法,所以Edmonds_Karp算法就是规定了Ford-Fulkerson找增广路的方法,仅此而已。

但这么一修改,复杂度发生了惊人的变化。

在说明Edmonds_Karp的复杂度为O(n*m^2)前,希望你已经提前知道了一些基本概念,如层次网络。

Edmonds_Karp本质是什么?不就是最短增广路算法,为什么最短,显然这是由BFS的性质决定的。

大家知道层次网络中只有第i层指向第i+1层的边,假设边(u,v),那么d[u]+1=d[v],又在层次网络中找到一条增广路,(u,v)是该增广路上权值最小的边(称作关键边),也就是这条增广路的可增广量,一经增广这条边将在层次网络中消失,于此同时会产生反向边(v,u),现在我们来考虑(u,v)总共可以成为 多少次关键边。从上面描述中可知,关键边一经增广就消失(流量为0),那如何才能再成为一次关键边,显然当(v,u)增广时,会导致(u,v)的流量增加,这样(u,v)将有资格再次成为键边。

我们来看两个等式d[u]+1=d[v],d[v']+1=d[u']{反向边(v,u)在层次网络中的等式}

注意:后一个等式增广晚于前一个,所以增广路增长(这就是最短增广路的本质,可以证明)。也就是d[v']>d[v],代入可得:

d[u']=d[v']+1>d[v]+1=d[u]+2,这个说明一条边前后两次成为关键边,u的层次会增加2,而u的层次至多从2变到n-1(u不会是源点和汇点),因此(u,v)最多有(n-2)/2次能够成为关键边,整个层次网络最多O(m)条边,因此关键边条数O(mn),而每找到一条增广路就会有一条关键边消失,因此最多有O(mn)条增广路,也就是BFS的执行次数最多为O(mn)次,而BFS的复杂度可认为O(m),因此总复杂度O(n*m^2),具体实现过程可以参考其他资料,比较简单的!

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 210
using namespace std;

const int inf=0x3f3f3f3f;
int cap[Maxn][Maxn]; //边容量
int flow[Maxn][Maxn]; //边实际流量
int pre[Maxn]; //增广路节点前驱
int alpha[Maxn]; //改进量
int q[Maxn]; //队列
int m,n; //边,节点数
void init(){
    memset(cap,0,sizeof cap);
    memset(flow,0,sizeof flow);
}
int Edmonds_Karp(int src,int t){ //源点,汇点
    int maxflow=0;
    while(1){
        memset(alpha,0,sizeof alpha);
        alpha[src]=inf; //源点初始化无穷大
        pre[src]=-1;
        int s=0,e=-1;
        q[++e]=src;
        while(s<=e&&!alpha[t]){ //bfs找增广路
            int u=q[s++];
            for(int i=1;i<=n;i++){
                if(!alpha[i]&&flow[u][i]<cap[u][i]){
                    pre[i]=u;
                    alpha[i]=min(alpha[u],cap[u][i]-flow[u][i]);
                    q[++e]=i;
                }
            }
        }
        if(!alpha[t]) break; //找不到增广路
        int k=t;
        while(pre[k]!=-1){
            flow[pre[k]][k]+=alpha[t];
            flow[k][pre[k]]-=alpha[t];
            k=pre[k];
        }
        maxflow+=alpha[t];
    }
    return maxflow;
}
int main()
{
    int u,v,c;
    while(~scanf("%d%d",&m,&n)){
        init();
        while(m--){
            scanf("%d%d%d",&u,&v,&c);
            cap[u][v]+=c;
        }
        printf("%d\n",Edmonds_Karp(1,n));
    }
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值