最大流问题

暂时最大流问题我就先掌握这一种算法吧
基本的最大流问题:

EK算法:(基于BFS)
每一次BFS更新一条路径,虽然都会入队列,但是由于以下条件保证点不会交叉,所以只有一条到终点的路径会更新流量。

if(!res[v] && map[u][v]>flow[u][v])

注意更新flow矩阵的时候是这样的:

while (u != start)
            {
                flow[pre[u]][u] += res[end];
                flow[u][pre[u]] -= res[end];
                u = pre[u];
            }

表示从flow[pre[u]][u]的这条边的流量可以增加res[end]这么多,反向的流量响应的减少,下一次在计算反向流量的时候也许不等式 mp[u][pre[u]]>flow[u][pre[u]]成立
http://www.cnblogs.com/jackge/archive/2013/04/10/3012182.html
//15MS 2064K

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>

using namespace std;

const int VM=220;
const int INF=0x3f3f3f3f;

int n,m,max_flow;   //max_flow是最大流
int map[VM][VM],flow[VM][VM];   // map[i][j]是每条边的容量,flow[i][j]是每条边的流量 
int res[VM],pre[VM];    //res[]是每个点的剩余流量,pre[]是每个点的父亲

int EK(int src,int des){
    max_flow=0;
    queue<int> q;
    while(!q.empty())
        q.pop();
    memset(flow,0,sizeof(flow));    //最开始每条边的流量都是0
    while(1){
        memset(res,0,sizeof(res));  //残余流量得变0,一开始所有点都没流入对吧
        res[src]=INF;   //源点嘛,剩余流量无限是必须的...
        q.push(src);    //从源点开始进行BFS找增广路
        int u,v;
        while(!q.empty()){
            u=q.front();
            q.pop();
            for(v=1;v<=m;v++)       //遍历所有点,找可行边
                if(!res[v] && map[u][v]>flow[u][v]){    //该点剩余流量为0 且 容量大于流量,也就是找到了新的结点 
                    pre[v]=u;   //找到新结点,父节点得记录一下吧
                    q.push(v);
                    res[v]=min(res[u],map[u][v]-flow[u][v]);    //如果u的剩余流量能填满uv就填满,不能的话就把u这点的流量全部流向uv 
                }
        }
        if(res[des]==0)     //如果当前已经是最大流,汇点没有残余流量
            return max_flow;
        for(u=des;u!=src;u=pre[u]){     //如果还能增广,那么回溯,从汇点往回更新每条走过的边的流量
            flow[pre[u]][u]+=res[des];  //更新正向流量   (注意这里更新的是流量,而不是容量)
            flow[u][pre[u]]-=res[des];  //更新反向流量
        }
        max_flow+=res[des];
    }
}

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d%d",&n,&m)){
        memset(map,0,sizeof(map));
        memset(pre,0,sizeof(pre));
        int u,v,w;
        while(n--){
            scanf("%d%d%d",&u,&v,&w);
            map[u][v]+=w;   //有重边
        }
        printf("%d\n",EK(1,m));
    }
    return 0;
}

比较完整的一个做法:
http://www.cnblogs.com/gabo/archive/2012/08/05/2623531.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值