[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门

Posted PushyTao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门相关的知识,希望对你有一定的参考价值。

题目链接

题目描述

给出一个包含 n n n 个点和 m m m 条边的有向图(下面称其为网络) G = ( V , E ) G=(V,E) G=(V,E),该网络上所有点分别编号为 1 ∼ n 1 \\sim n 1n,所有边分别编号为 1 ∼ m 1\\sim m 1m,其中该网络的源点为 s s s,汇点为 t t t,网络上的每条边 ( u , v ) (u,v) (u,v) 都有一个流量限制 w ( u , v ) w(u,v) w(u,v)和单位流量的费用 c ( u , v ) c(u,v) c(u,v)

你需要给每条边 ( u , v ) (u,v) (u,v) 确定一个流量 f ( u , v ) f(u,v) f(u,v),要求:

  1. 0 ≤ f ( u , v ) ≤ w ( u , v ) 0 \\leq f(u,v) \\leq w(u,v) 0f(u,v)w(u,v) (每条边的流量不超过其流量限制);
  2. ∀ p ∈ { V ∖ { s , t } } \\forall p \\in \\{V \\setminus \\{s,t\\}\\} p{V{s,t}} ∑ ( i , p ) ∈ E f ( i , p ) = ∑ ( p , i ) ∈ E f ( p , i ) \\sum_{(i,p) \\in E}f(i,p)=\\sum_{(p,i)\\in E}f(p,i) (i,p)Ef(i,p)=(p,i)Ef(p,i)(除了源点和汇点外,其他各点流入的流量和流出的流量相等);
  3. ∑ ( s , i ) ∈ E f ( s , i ) = ∑ ( i , t ) ∈ E f ( i , t ) \\sum_{(s,i)\\in E}f(s,i)=\\sum_{(i,t)\\in E}f(i,t) (s,i)Ef(s,i)=(i,t)Ef(i,t) (源点流出的流量等于汇点流入的流量)。

定义网络 G G G 的流量 F ( G ) = ∑ ( s , i ) ∈ E f ( s , i ) F(G)=\\sum_{(s,i)\\in E}f(s,i) F(G)=(s,i)Ef(s,i),网络 G G G 的费用 C ( G ) = ∑ ( i , j ) ∈ E f ( i , j ) × c ( i , j ) C(G)=\\sum_{(i,j)\\in E} f(i,j) \\times c(i,j) C(G)=(i,j)Ef(i,j)×c(i,j)

你需要求出该网络的最小费用最大流,即在 F ( G ) F(G) F(G) 最大的前提下,使 C ( G ) C(G) C(G) 最小。

输入格式

输入第一行包含四个整数 n , m , s , t n,m,s,t n,m,s,t,分别代表该网络的点数 n n n,网络的边数 m m m,源点编号 s s s,汇点编号 t t t
接下来 m m m 行,每行四个整数 u i , v i , w i , c i u_i,v_i,w_i,c_i ui,vi,wi,ci,分别代表第 i i i 条边的起点,终点,流量限制,单位流量费用。

输出格式

输出两个整数,分别为该网络的最大流 F ( G ) F(G) F(G),以及在 F ( G ) F(G) F(G) 最大的前提下,该网络的最小费用 C ( G ) C(G) C(G)

输入输出样例

4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
50 280

说明/提示
对于 100 % 100\\% 100% 的数据, 1 ≤ n ≤ 5 × 1 0 4 1 \\leq n \\leq 5\\times 10^4 1n5×104 1 ≤ m ≤ 5 × 1 0 4 1 \\leq m \\leq 5 \\times 10^4 1m5×104 1 ≤ s 1 \\leq s 1s , t ≤ n t \\leq n tn 0 ≤ w i , c i ≤ 1 0 3 0 \\leq w_i,c_i \\leq 10^3 0wi,ci103 ,且该网络的最大流和最小费用 ≤ 2 31 − 1 \\leq 2^{31} - 1 2311
输入数据随机生成。

思路:
EK算法类似,但每次用 B e l l m a n − F o r d Bellman-Ford BellmanFord 算法而非 B F S BFS BFS(其实差不多)找增广路。
只要初始流是该流量下的最小费用可行流,每次增广之后的新流都是新流量下的最小费用流。
费用值可正可负

typedef pair<ll, ll> PLL;
struct Edge {
    int u, v, cap, flow, cost;
    Edge(int _u, int _v, int _cap, int _flow, int _cost) {
        u = _u, v = _v, cap = _cap, flow = _flow, cost = _cost;
    }
};
struct MinCostMaxFlow {
    int n, m;
    vector<Edge> edges;
    vector<int> G[maxn];
    int vis[maxn], dis[maxn], p[maxn], a[maxn];
    void init(int x) {
        this->n = x;
        for (int i = 0; i <= x; i++) G[i].clear();
        edges.clear();
    }
    void add(int u, int v, int cap, int cost) {
        edges.push_back(Edge(u, v, cap, 0, cost));
        edges.push_back(Edge(v, u, 0, 0, -cost));
        m = edges.size();
        G[u].push_back(m - 2);
        G[v].push_back(m - 1);
    }
    bool BellmanFord(int s, int t, ll &flow, ll &cost) {
        for (int i = 0; i <= n; i++) dis[i] = 0x3f3f3f3f;
        memset(vis, 0, sizeof vis);
        queue<int> que;
        que.push(s);
        dis[s] = 0, vis[s] = 0, p[s] = 0, a[s] = 0x3f3f3f3f;
        while (que.size()) {
            int u = que.front();
            que.pop();
            vis[u] = 0; /// not in the queue
            for (int i = 0; i < G[u].size(); i++) {
                int id = G[u][i];
                Edge e = edges[id];
                int to = e.v;
                if (e.cap > e.flow && dis[to] > dis[u] + e.cost) {
                    dis[to] = dis[u] + e.cost;
                    p[to]   = id;
                    a[to]   = min(a[u], e.cap - e.flow);
                    if (!vis[to]) {
                        que.push(to[洛谷 P3381] 最小费用最大流 | 模板 Bellman-Ford寻找增广路 入门

最小费用最大流基础模板(洛谷3381)

洛谷 [P3381] 最小费用最大流模版

P3381 模板最小费用最大流

P3381 模板最小费用最大流

P3381 模板最小费用最大流