Luogu P338 最小费用最大流___费用流

题目大意:

给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=5000,M<=50000

题解:

在 Edmonds-Karp求解最大流的基础上,
用BFS寻找一条增广路改为用SPFA寻找一条单位费用之和最小的增广路,在在残量网络上求最短路,即可求出最小费用最大流。注意:一条反向边y—>x的费用应设为-x到y的单位费用.

代码:

#include <bits/stdc++.h>
#define INF 2333333
#define M 50005
#define N 5005

using namespace std;

int n,m,cnt=1,maxflow,ans,ls[N],v[N],incf[N],dis[N],pre[N];

struct edge {
    int to,num,cost,next;
} e[M*2];

void add(int u, int v, int w, int f) {
    cnt++; e[cnt].to=v; e[cnt].num=w; e[cnt].cost=f; e[cnt].next=ls[u]; ls[u]=cnt; 
    cnt++; e[cnt].to=u; e[cnt].num=0; e[cnt].cost=-f; e[cnt].next=ls[v]; ls[v]=cnt;
}

bool spfa(int s, int t){
    for (int i=1; i<=n; i++) dis[i]=INF;
    memset(v,0,sizeof(v));
    queue <int> Q;
    Q.push(s); 
    v[s]=1; dis[s]=0;
    incf[s]=INF;
    while (Q.size()){
        int u=Q.front();
        Q.pop();
        for (int i=ls[u]; i; i=e[i].next)
             if (e[i].num && dis[e[i].to]>dis[u]+e[i].cost){
                dis[e[i].to]=dis[u]+e[i].cost;
                incf[e[i].to]=min(incf[u],e[i].num);
                pre[e[i].to]=i;
                if (!v[e[i].to]){
                     Q.push(e[i].to);
                     v[e[i].to]=1;
                }
            }
        v[u]=0;
    }
    return dis[t]!=INF;
}

void update(int s, int t){
    int x=t;
    while (x!=s){
        int i=pre[x];
        e[i].num-=incf[t];
        e[i^1].num+=incf[t];
        x=e[i^1].to;
    }
    maxflow+=incf[t];
    ans+=dis[t]*incf[t];
}

void edmonds_karp(int s, int t){
    while (spfa(s,t)) update(s,t);

}

int main() {
    int s, t;
    scanf("%d%d%d%d",&n,&m,&s,&t);
    int u,v,w,f;
    for (int i=1; i<=m; i++)
        {
             scanf("%d%d%d%d",&u,&v,&w,&f);
             add(u,v,w,f);
       }
    edmonds_karp(s,t);
    printf("%d %d\n",maxflow,ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值