zoukankan      html  css  js  c++  java
  • 【2020牛客多校】2020牛客暑期多校训练营(第一场)H-Minimum-cost Flow——网络流

    题目链接

    大致题意

    给出一个费用流图,每条边的流量上限相同且不固定。
    (q)个询问,每个询问中给出每条边的流量上限(分数,且保证(leq 1))。当图中的流量为 (1) 个单位的时候,求出此时的费用。

    分析

    首先是询问个数,有(1e5)次询问,则需要预处理整个图,然后O(1)作答才可以过
    然后注意到题目中给出的数据规模,图的边数只有(100)

    首先由于边的流量均为分数((frac{u}{v})),而总流量为 (1) 个单位。我们先扩大(frac{v}{u})倍,将每条边的流量固定为 (1) 个单位,此时流量为 (frac{v}{u}) 个单位

    考虑在最大流使用 SPFA 查找路径时,当查找到一条路径时,此路径的流量一定为 (1) (根据上述的设定)。由于采用的本身便是最短路查找路径,得到的路径的费用为当前网络图下的最低费用。

    所以可以稍微修改费用流板子中的一部分代码,使得每次得到路径并结算费用时,将每次得到的路径费用记录下来并保存。

    #define ll long long
    
    const int maxn = 100;      //点数
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int from, to, cap, flow, cost;
    
        Edge(int u, int v, int c, int f, int cc)
                : from(u), to(v), cap(c), flow(f), cost(cc) {}
    };
    
    vector<ll> res;
    
    struct MCMF {
        int n, m;
        vector<Edge> edges;
        vector<int> G[maxn];
        int inq[maxn];  //是否在队列中
        int d[maxn];    //bellmanford
        int p[maxn];    //上一条弧
        int a[maxn];    //可改进量
        void init(int n) {
            this->n = n;
            for (int i = 0; i <= n; ++i) G[i].clear();
            edges.clear();
        }
    
        void addEdge(int from, int to, int cap, int cost) {
            edges.emplace_back(Edge(from, to, cap, 0, cost));
            edges.emplace_back(Edge(to, from, 0, 0, -cost));
            m = int(edges.size());
            G[from].emplace_back(m - 2);
            G[to].emplace_back(m - 1);
        }
    
        bool spfa(int s, int t, int &flow, ll &cost) {
            for (int i = 1; i <= n; ++i) d[i] = INF;
            memset(inq, 0, sizeof(inq));
            d[s] = 0;
            inq[s] = 1;
            p[s] = 0;
            queue<int> q;
            a[s] = INF;
            q.push(s);
            while (!q.empty()) {
                int u = q.front();
                q.pop();
                inq[u] = 0;
                for (int i = 0; i < int(G[u].size()); ++i) {
                    Edge &e = edges[G[u][i]];
                    if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                        d[e.to] = d[u] + e.cost;
                        p[e.to] = G[u][i];
                        a[e.to] = min(a[u], e.cap - e.flow);
                        if (!inq[e.to]) {
                            q.push(e.to);
                            inq[e.to] = 1;
                        }
                    }
                }
            }
            if (d[t] == INF) return false;
            flow += a[t];
            cost += (ll) d[t] * (ll) a[t];
            res.push_back(d[t]);
            for (int u = t; u != s; u = edges[p[u]].from) {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            return true;
        }
    
        int MincostMaxflow(int s, int t, ll &cost) {
            int flow = 0;
            cost = 0;
            while (spfa(s, t, flow, cost));
            return flow;
        }
    } mcmf;
    

    通过 res 数组记录下所有得到的路径的费用

    而后分解流量。对于每一次询问,从 res 数组中从开始取值每次取出一条路径来提供 (1) 个单位的流量,直到满足流量要求,则停止取值并输出答案。

    虽然 (1 leq u, v leq 1e9),可能需要循环遍历 (1e9) 次才能出结果,但是由于图中每条边的容量都是 (1),所以对于每一条路径,它只有被完全占用和完全空闲两种状态,而边数只有 (100) 条,即整个网络的最大流量只能是 (100) 个单位,即最多遍历 (100) 次,则复杂度不超过 (100 * 1e5 = 1e7),当 (MAX\_FLOW * u < v) 时,则无解,输出 (-1)

    注意一下乘法运算只需要考虑分子部分,分母部分不需要参与运算,在最后需要分子分母都除以 (gcd) 以保证最简

    AC code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    
    const int maxn = 100;      //点数
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int from, to, cap, flow, cost;
    
        Edge(int u, int v, int c, int f, int cc)
                : from(u), to(v), cap(c), flow(f), cost(cc) {}
    };
    
    vector<long long> res;
    
    struct MCMF {
        int n, m;
        vector<Edge> edges;
        vector<int> G[maxn];
        int inq[maxn];  //是否在队列中
        int d[maxn];    //bellmanford
        int p[maxn];    //上一条弧
        int a[maxn];    //可改进量
        void init(int n) {
            this->n = n;
            for (int i = 0; i <= n; ++i) G[i].clear();
            edges.clear();
        }
    
        void addEdge(int from, int to, int cap, int cost) {
            edges.emplace_back(Edge(from, to, cap, 0, cost));
            edges.emplace_back(Edge(to, from, 0, 0, -cost));
            m = int(edges.size());
            G[from].emplace_back(m - 2);
            G[to].emplace_back(m - 1);
        }
    
        bool spfa(int s, int t, int &flow, ll &cost) {
            for (int i = 1; i <= n; ++i) d[i] = INF;
            memset(inq, 0, sizeof(inq));
            d[s] = 0;
            inq[s] = 1;
            p[s] = 0;
            queue<int> q;
            a[s] = INF;
            q.push(s);
            while (!q.empty()) {
                int u = q.front();
                q.pop();
                inq[u] = 0;
                for (int i = 0; i < int(G[u].size()); ++i) {
                    Edge &e = edges[G[u][i]];
                    if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                        d[e.to] = d[u] + e.cost;
                        p[e.to] = G[u][i];
                        a[e.to] = min(a[u], e.cap - e.flow);
                        if (!inq[e.to]) {
                            q.push(e.to);
                            inq[e.to] = 1;
                        }
                    }
                }
            }
            if (d[t] == INF) return false;
            flow += a[t];
            cost += (ll) d[t] * (ll) a[t];
            res.push_back(d[t]);
            for (int u = t; u != s; u = edges[p[u]].from) {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            return true;
        }
    
        int MincostMaxflow(int s, int t, ll &cost) {
            int flow = 0;
            cost = 0;
            while (spfa(s, t, flow, cost));
            return flow;
        }
    } mcmf;
    
    int n, m;
    
    void solve() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.precision(10);
        cout << fixed;
        while (cin >> n >> m) {
            mcmf.init(n + 10);
            res.clear();
            for (int i = 0; i < m; ++i) {
                int u, v, f;
                cin >> u >> v >> f;
                mcmf.addEdge(u, v, 1, f);
            }
            ll cost = 0;
            ll mf = mcmf.MincostMaxflow(1, n, cost);
            int q;
            cin >> q;
            while (q--) {
                ll u, v;
                cin >> u >> v;
                if (mf * u < v) {
                    cout << "NaN" << '
    ';
                    continue;
                }
                ll sum = 0;
                ll ans = 0;
                for (auto item : res) {
                    if (sum + u <= v) {
                        sum += u;
                        ans += item * u;
                    } else {
                        ans += (v - sum) * item;
                        break;
                    }
                }
                ll g = __gcd(ans, v);
                cout << ans / g << '/' << v / g << '
    ';
            }
        }
    }
    
    signed main() {
        ios_base::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    #ifdef ACM_LOCAL
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
        int test_index_for_debug = 1;
        char acm_local_for_debug;
        while (cin >> acm_local_for_debug) {
            if (acm_local_for_debug == '$') exit(0);
            cin.putback(acm_local_for_debug);
            if (test_index_for_debug > 20) {
                throw runtime_error("Check the stdin!!!");
            }
            auto start_clock_for_debug = clock();
            solve();
            auto end_clock_for_debug = clock();
            cout << "Test " << test_index_for_debug << " successful" << endl;
            cerr << "Test " << test_index_for_debug++ << " Run Time: "
                 << double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
            cout << "--------------------------------------------------" << endl;
        }
    #else
        solve();
    #endif
        return 0;
    }
    
  • 相关阅读:
    数据库设计规则
    了解何时使用 Override 和 New 关键字(C# 编程指南)
    Why we use stored procedure than Sql statement?
    HTML条件注释和javascript条件注释
    <%# %> 和 <% %> 有什么区别?
    short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
    如何实现 Visual Studio 2005 中远程调试
    认识延迟时间为0的setTimeout(转)
    Web应用程序中(VS2005+SP1)添加App_Code
    AWStats 一个不错的Web/Mail/FTP日志分析工具
  • 原文地址:https://www.cnblogs.com/mauve-hkq/p/13303915.html
Copyright © 2011-2022 走看看