zoukankan      html  css  js  c++  java
  • [洛谷 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 1sim 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) imes 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 imes 10^4 1n5×104 1 ≤ m ≤ 5 × 1 0 4 1 leq m leq 5 imes 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);
                            vis[to] = 1;
                        }
                    }
                }
            }
            if (dis[t] >= 0x3f3f3f3f) return false;
            flow += a[t];
            cost += 1LL * dis[t] * 1LL * a[t];
            for (int u = t; u != s; u = edges[p[u]].u) {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            return true;
        }
        PLL MinCostAndMaxFlow(int s, int t) {
            ll flow = 0;
            ll cost = 0;
            while (BellmanFord(s, t, flow, cost));
            return {flow, cost};
        }
    } solve;
    int n, m, s, t;
    int main() {
        cin >> n >> m >> s >> t;
        solve.init(n);
        for (int i = 1; i <= m; i++) {
            int u = read, v = read, flow = read, cost = read;
            solve.add(u, v, flow, cost);
        }
        PLL ans = solve.MinCostAndMaxFlow(s, t);
        cout << ans.first << ' ' << ans.second << endl;
        return 0;
    }
    
  • 相关阅读:
    Zookeeper 3.4 官方文档翻译
    西门子PLC学习笔记六-(Step7指令简单介绍)
    Leetcode[129]-Sum Root to Leaf Numbers
    一个Exchange 2010 的password不定期弹框的问题处理,希望对大家可以有所帮助。
    数据库分表和分库的原理及基于thinkPHP的实现方法
    电力企业信息化建设方案之调度信息报送系统
    自己定义控件三部曲视图篇(一)——測量与布局
    VS自己定义project向导开发(Custom Wizard)
    Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决的方法
    ALM11需求和测试覆盖率图解1
  • 原文地址:https://www.cnblogs.com/PushyTao/p/15459803.html
Copyright © 2011-2022 走看看