【模板】最小费用最大流(网络流)/洛谷P3381

题目链接

https://www.luogu.com.cn/problem/P3381

题目大意

输入格式
第一行包含四个正整数 \(n,m,s,t\),分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来\(m\)行,每行包含四个正整数 \(u_i,v_i,w_i,f_i\),表示第 \(i\) 条有向边从 \(u_i\) 出发,到达 \(v_i\),边权为 \(w_i\)(即该边最大流量为 \(w_i\) ),单位流量的费用为 \(f_i\)
输出格式
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

题目解析

(待补充,咕咕咕。。。)

参考代码

\(SPFA\)的两个优化可以有效提升速度。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = (1LL) << 32;
const int N = 5005;
struct Edge{
    int u, v;
    ll cap, cost, flow;
};
vector <Edge> e;
vector <int> G[N];
ll a[N], d[N];
int inQ[N], p[N];
int n, m, s, t, cnt;

void addEdge(int u, int v, ll cap, ll cost, int i)
{
    e.push_back((Edge){u, v, cap, cost, 0});
    e.push_back((Edge){v, u, 0, -cost, 0});
    G[u].push_back(i);
    G[v].push_back(i^1);
}
bool SPFA(ll &flow, ll &cost)
{
    for (int i = 0; i <= cnt; ++i) d[i] = INF;
    memset(a, 0, sizeof a);
    a[s] = INF, d[s] = 0;
    deque <int> Q;
    Q.push_back(s);
    inQ[s] = 1;
    while (!Q.empty())
    {
        int x = Q.front();
        Q.pop_front();
        inQ[x] = 0;
        for (int i = 0; i <G[x].size(); ++i)
        {
            Edge &b = e[G[x][i]];
            if (b.cap > b.flow && d[b.v] > d[x] + b.cost)
            {
                d[b.v] = d[x] + b.cost;
                p[b.v] = G[x][i];
                a[b.v] = min(a[x], b.cap-b.flow);
                if (!inQ[b.v] && b.v != t)//优化1:终点无需入队
                {
                    inQ[b.v] = 1;
                    if (!Q.empty() && d[b.v] < d[Q.front()]) Q.push_front(b.v);//优化2:small label first
                    else Q.push_back(b.v);
                }
            }
        }
    }
    if (d[t] == INF) return false;
    flow += a[t];
    cost += a[t]*d[t];
    for (int u = t; u != s; u = e[p[u]].u)
    {
        e[p[u]].flow += a[t];
        e[p[u]^1].flow -= a[t];
    }
    return true;
}
ll mincostMaxflow(ll &cost)
{
    cnt = n; //cnt: count nodes
    ll flow = 0;
    while (SPFA(flow, cost));
    return flow;
}
int main()
{
    int u, v;
    ll w, c;
    scanf("%d%d%d%d", &n, &m, &s, &t);
    for (int i = 0; i < m; ++i)
    {
        scanf("%d%d%lld%lld", &u, &v, &w, &c);
        addEdge(u, v, w, c, i << 1);
    }
    w = mincostMaxflow(c=0);
    printf("%lld %lld\n", w, c);
    return 0;
}

感谢支持!

posted @ 2020-08-26 18:46  Chiron-zy  阅读(147)  评论(0编辑  收藏  举报