Fork me on GitHub

【模板】最小费用最大流

给出一个容量网络,那他的最大流一定是一个定值(即使是有多个一样的最大值)。
所以我们从开始的可行流开始增广时,最终的增广量是一定的。
所以为了满足最小费用我们只需要每次找最小费用的增广路即可,直到流量为最大值。
这个问题仅仅是在求增广路时先考虑费用最小的增广路,其他思想和EK思想一样。
我们学过SPFA求最短路算法(bellman-ford的队列优化),所以我们将弧的费用看做是路径长度,即可转化为求最短路的问题了。只需要所走的最短路满足两个条件即可:1剩余流量不为0,2路径变短d[v]>d[u]+cost< u,v> 。

https://www.luogu.org/problem/show?pid=3381#sub
这里写图片描述

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int n,m,S,T;
int num[100005],cap[100005],cost[100005],nxt[100005],head[5005],cnt=1;//cap记残余流量,cost记费用
int dis[5005],flow[5005],xb[5005];//xb记链表数组的下标,dis用于spfa
int pre[5005];
bool used[5005];
int mflow=0,mcost=0;
void add(int from,int to,int ca,int co)
{
    cnt++;//从 2 开始 ,若从0开始,会导致找点时循环停止!!!
    num[cnt]=to;
    nxt[cnt]=head[from];
    head[from]=cnt;
    cost[cnt]=co;
    cap[cnt]=ca;
}
int bfs(int s,int t)
{
    memset(dis,127,sizeof(dis));
    memset(used,false,sizeof(used));
    for(int i=1;i<=n;i++) pre[i]=-1;
    queue <int> q;
    while(!q.empty()) q.pop();

    q.push(s);
    pre[s]=0;
    dis[s]=0; 
    used[s]=true;
    flow[s]=dis[0];

    while(!q.empty())
    {
        int k=q.front();
        q.pop();
        used[k]=false;

        for(int i=head[k];i;i=nxt[i])
        {
            int to=num[i];
            if(cap[i]>0&&dis[to]>dis[k]+cost[i])//在spfa判断条件基础上,加上剩余流量>0
            {
                xb[to]=i;
                dis[to]=dis[k]+cost[i];
                flow[to]=min(flow[k],cap[i]);
                if(!used[to]) used[to]=true,q.push(to);
                pre[to]=k;
            }
        }
    }
    if(pre[t]==-1) return -1;
    else return flow[t]; 
}
void maxflow(int s,int t)
{
    int d;
    while(bfs(s,t)!=-1)
    {
        d=flow[t];
        int k=t;
        while(k!=s)
        {
            cap[xb[k]]-=d;
            cap[xb[k]^1]+=d;

            k=pre[k];
        }
        mflow+=d;
        mcost+=d*dis[t];//每条边上的流量为d,dis[t]为每条边单位流量费用之和
        if(d==0) break;
    }
    return;
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1;i<=m;i++)
    {
        int u,v,w,f;
        scanf("%d%d%d%d",&u,&v,&w,&f);
        add(u,v,w,f);
        add(v,u,0,-f);
    }

    maxflow(S,T);

    printf("%d %d",mflow,mcost);
    return 0;
} 
posted @ 2017-05-03 15:18  primes  阅读(145)  评论(0编辑  收藏  举报