最大网络流算法

最大网络流算法之增广路算法

理论讲解

为了在一个图中得到最大流,可以从任何一个可行流开始,沿着增广路对网络流进行增广,知道图中不存在增广路为止。

如何找增广路:从源点S出发用求最短路的算法根据边的容量 流量 找一条最短路 记录下来该路径,走一边该路径,找到该路中(容量-流量的最小值),对该路径上所有边的流量都加上该最小值。

直到找不到图中的增广路,即说明该网路的流量已经达到了最大。

附上代码:

 

queue<int> q;
int bfs()     //找增广路径   用spfa算法
{
    int i,t;
    while(!q.empty()) q.pop();   //清空队列
    memset(path,-1,sizeof(path));
    path[start]=0,flow[start]=INF;
    q.push(start);
    while(!q.empty())
    {
        t=q.front();
        q.pop();
        if(t==end) break;
        for(i=1; i<=m; i++)
        {
            if(i!=start && path[i]==-1 && map[t][i])
            {
                flow[i]=flow[t]<map[t][i]?flow[t]:map[t][i];
                q.push(i);
                path[i]=t;
            }
        }
    }
    if(path[end]==-1) return -1;      //没有找到
    return flow[m];                   //一次遍历之后的流量增量
}
int Edmonds_Karp()
{
    int max_flow=0,step,now,pre;
    while((step=bfs())!=-1)           //找不到增路径时退出
    {
        max_flow+=step;
        now=end;
        while(now!=start)
        {
            pre=path[now];
            map[pre][now]-=step;      //更新正向边的实际容量
            map[now][pre]+=step;      //添加反向边
            now=pre;
        }
    }
    return max_flow;    //返回最大流
}

</pre></p><p><span style="font-size:18px;"> </span></p><p><span style="font-size:18px;"> </span></p><p><span style="font-size:18px;">网络流入门例题  <a target=_blank href="http://poj.org/problem?id=1273"><span style="color:rgb(102, 102, 102);">http://poj.org/problem?id=1273</span></a></span></p><h3><span style="font-size:18px;">题目大意 <u> <a target=_blank href="http://blog.csdn.net/kg_second/article/details/8041768"><span style="color:rgb(73, 73, 73);">每当下雨,农夫</span><span style="color:rgb(73, 73, 73);">住</span><span style="color:rgb(73, 73, 73);">地方周围就变成了一个池塘,这让他很</span><span style="color:rgb(73, 73, 73);">高兴</span><span style="color:rgb(73, 73, 73);">,所以决心要把这个问题解</span></a><a target=_blank href="http://blog.csdn.net/kg_second/article/details/8041768"><span style="color:rgb(73, 73, 73);">决掉,所以他就在四周建造了一些渠沟排水,把这水排到一个小溪处。编号为<span style="font-family:Arial;">1</span><span style="font-family:宋体;">的节点作为池塘,编号为</span><span style="font-family:Arial;">n</span><span style="font-family:宋体;">的地方作为小溪。求最大排水量</span></span></a></u></span></h3><p><span style="font-size:18px;"><span style="color:rgb(73, 73, 73);">注意重边的情况就可以了</span><span style="color:rgb(73, 73, 73);">。</span></span></p><p><span style="font-size:18px;">代码</span></p><p><span style="font-size:18px;"></span><pre name="code" class="cpp">#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <functional>
#define PI acos(-1.0)
#define esp 1e-8
#define MAXN 220
#define mem(a) memset(a,0,sizeof(a));
#define mem_1(a) memset(a,-1,sizeof(a));
using namespace std;
const int INF = 0x7FFFFFFF;
int cap[MAXN][MAXN];
int n,m;
int path[MAXN],flow[MAXN];
int bfs()
{
    mem_1(path);
    path[1] = 0;
    flow[1] = INF;
    queue<int> Q;
    Q.push(1);
    while(!Q.empty())
    {
        int now = Q.front();
        Q.pop();
        if(now==m) break;
        for(int v = 1;v<=m;v++)
        {
            if(v!=1 && path[v]==-1 && cap[now][v] )
            {
                path[v] = now;
                Q.push(v);
                flow[v] = min(flow[now],cap[now][v]);
            }
        }


    }
    if(path[m]==-1)  return -1;
    return flow[m];
}
int E_K()
{
    int xx,pre;
    int ans_flow = 0;
    while( (xx = bfs())!=-1)
    {
        ans_flow+=xx;
        int now = m;
        while(now!=1)
        {
            pre = path[now];
            cap[pre][now]-=xx;
            cap[now][pre]+=xx;
            now = pre;
        }
    }
    return ans_flow;
}
int main()
{
    int tem1,tem2,tem3;
    while(cin >> n >> m)
    {
        mem(cap);
        for(int i=1;i<=n;i++)
        {
            cin >> tem1 >> tem2 >> tem3;
            cap[tem1][tem2] +=tem3;
        }
        cout << E_K() << endl;
    }
    return 0;
}
暑假集训生活开始了。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值