LibreOJ #102.最小费用最大流

题目描述

这是一道模板题。

给定一个图,每条边有容量和费用,使用每条边的单位流量需要支付特定的费用。给定源点 1 1 1 和汇点 n n n,求图的最大流和最大流需要支付的最小费用。

输入格式

第一行两个整数  n n m m,表示有  nn 个点  mm 条边。

从第二行开始的之后 m 行,每行四个整数 si s_i ticiwi w_i 表示一条从 si s_i ti 的边,容量为 ci c_i ,单位流量需要支付的费用为 wi

输出格式

一行两个整数,分别表示最大流和最大流需要支付的最小费用。

样例

样例输入

8 23
2 3 2147483647 1
1 3 1 1
2 4 2147483647 2
1 4 1 2
2 8 2 0
3 5 2147483647 3
1 5 1 3
3 6 2147483647 4
1 6 1 4
3 8 2 0
3 2 2147483647 0
4 6 2147483647 5
1 6 1 5
4 7 2147483647 6
1 7 1 6
4 8 2 0
4 2 2147483647 0
5 8 0 0
5 2 2147483647 0
6 8 0 0
6 2 2147483647 0
7 8 0 0
7 2 2147483647 0

样例输出

6 24

数据范围与提示

1≤n≤400,0≤m≤15000,wi≥0保证输入数据、中间结果以及答案在 32 位有符号整数范围内。

题目思路

有点像 EK+spfa

AC代码

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 5000 + 10;
const int maxm = 50000 + 10;
const int inf = 0x7fffffff;
struct Edge{
    int to, w,dist, next;   //可将花费看成距离
};
Edge e[maxm * 2];
int head[maxn];      //用于静态链表
int dist[maxn];      //距离
int inq[maxn];       //是否在队列中
int flow[maxn];   
int pre[maxn];
int nume[maxn];      //记录边的编号,还可以求反边
int cnt;
int n, m,s,t,maxflow=0;
long long mincost=0;
void init(){
    for (int i = 0; i <= n; i++) head[i] = -1;
    s = 1; t = n;
    cnt = 0;
}
void addedge(int u, int v, int w,int dist){
    e[cnt].to = v; e[cnt].w = w; e[cnt].dist = dist;
    e[cnt].next = head[u]; head[u]= cnt++;
}
int spfa(){   
    queue<int> q;
    for (int i = 0; i <= n; i++) { dist[i] = inf; inq[i] = 0; }
    dist[s] = 0;  flow[s] = inf;
    q.push(s); inq[s] = 1;

    while (!q.empty()){
        int p = q.front(); q.pop();inq[p] = 0;

        for (int i = head[p]; ~i; i = e[i].next){
            int v = e[i].to;
            if (e[i].w > 0 && dist[v] > dist[p] + e[i].dist){
                dist[v] = dist[p] + e[i].dist;            //更新最短路(花费的角度)
                pre[v] = p;                               //记录路径
                nume[v] = i;                              //记录这个顶点的编号,i^1就是反向边
                flow[v] = min(flow[p],e[i].w);            //更新可行流
                if (!inq[v]){ q.push(v); inq[v] = 1; }
            }

        }
    }
    return dist[t] < inf;
}
void MCMF(){   //mcmf主体
    
    while (spfa()){     //如果不可增广,算法结束
        int p = t;
        while (p != s){
            e[nume[p]].w -= flow[t];
            e[nume[p]^1].w += flow[t];
            p = pre[p];
        }
        maxflow += flow[t];
        mincost += 1ll*flow[t] * dist[t];
    }
}
int main()
{
    cin >> n >> m ;
    int a, b, c, d;
    init();
    for (int i = 0; i < m; i++){
        cin >> a >> b >> c >> d;
        addedge(a, b, c, d);
        addedge(b, a, 0, -d);
    }
    MCMF();
    cout << maxflow << ' ' << mincost << endl;
    return 0;
}
View Code

题解效率

猜你喜欢

转载自www.cnblogs.com/looeyWei/p/10464391.html