zoukankan      html  css  js  c++  java
  • 【洛谷P4542】 [ZJOI2011]营救皮卡丘(费用流)

    洛谷

    题意:
    给出(n)个点,(m)条边,现在有(k,kleq 10)个人从(0)号点出发前往(n)点。
    规定若某个人想要到达(x)点,则(1)~(x-1)号点都有人到达过才行。
    每条边都有对应长度,问某一个人走到(n)点时,所有人走的路径长度和最小为多少。

    思路:

    • 直接考虑路径较为繁琐,我们可以直接考虑一个人摧毁的点集,发现点集中的点的标号是递增的。
    • (u)(v,u<v)的路径可能经过(0)~(v-1)中的任意一点,这里可以直接floyd预处理出来,那么两点之间的路径长度即可确定。
    • 考虑费用流。我们将点拆为(i,i')(i)连向(T)(S)连向(i')(i')连向(j,j>i)。容量都为(1),费用只有两点之间连边时才产生费用。最后(S)连向(0'),容量为(k),费用为(0)
    • 以上建图保证每个点只会被用一次,并且最后最多(k)条不重叠的单调递增的路径。
    • 直接跑最小费用流即可。

    其实就类似于求(k)个上升子序列,用流量来限制每个点只能选一次并且每个点都会选,并且选择两个点会附加费用。
    代码如下:

    /*
     * Author:  heyuhhh
     * Created Time:  2019/10/31 10:37:25
     */
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 1005, M = 20005;
    
    int n, m, k;
    
    struct E {
        int from, to, cp, v;
        E() {}
        E(int f, int t, int cp, int v) : from(f), to(t), cp(cp), v(v) {}
    };
    
    struct MCMF {
        int n, m, s, t;
        vector<E> edges;
        vector<int> G[N];
        bool inq[N];
        int d[N], p[N], a[M];
    
        void init(int _n, int _s, int _t) {
            n = _n; s = _s; t = _t;
            for(int i = 0; i <= n; i++) G[i].clear();
            edges.clear(); m = 0;
        }
    
        void addedge(int from, int to, int cap, int cost) {
            edges.emplace_back(from, to, cap, cost);
            edges.emplace_back(to, from, 0, -cost);
            G[from].push_back(m++);
            G[to].push_back(m++);
        }
    
        bool BellmanFord(int &flow, int &cost) {
            for(int i = 0; i <= n; i++) d[i] = INF;
            memset(inq, 0, sizeof inq);
            d[s] = 0, a[s] = INF, inq[s] = true;
            queue<int> Q; Q.push(s);
            while (!Q.empty()) {
                int u = Q.front(); Q.pop();
                inq[u] = false;
                for (int& idx: G[u]) {
                    E &e = edges[idx];
                    if (e.cp && d[e.to] > d[u] + e.v) {
                        d[e.to] = d[u] + e.v;
                        p[e.to] = idx;
                        a[e.to] = min(a[u], e.cp);
                        if (!inq[e.to]) {
                            Q.push(e.to);
                            inq[e.to] = true;
                        }
                    }
                }
            }
            if (d[t] == INF) return false;
            flow += a[t];
            cost += a[t] * d[t];
            int u = t;
            while (u != s) {
                edges[p[u]].cp -= a[t];
                edges[p[u] ^ 1].cp += a[t];
                u = edges[p[u]].from;
            }
            return true;
        }
    
        int go() {
            int flow = 0, cost = 0;
            while (BellmanFord(flow, cost)); 
            return cost;
        }
    } MM;
    
    int g[155][155];
    
    void run(){
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= n; j++) {
                g[i][j] = INF;
            }
        }
        for(int i = 1; i <= m; i++) {
            int u, v, w;
            cin >> u >> v >> w;
            g[u][v] = g[v][u] = min(g[u][v], w);
        }
        int S = 2 * n + 2, T = S + 1;
        for(int k = 0; k <= n; k++) {
            for(int i = 0; i <= n; i++) {
                for(int j = 0; j <= n; j++) {
                    if(k <= max(i, j)) {
                        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
                    }
                }   
            }
        }
        MM.init(T, S, T);
        for(int i = 0; i < n; i++) {
            for(int j = i + 1; j <= n; j++) {
                if(g[i][j] != INF) {
                    MM.addedge(i + n + 1, j, 1, g[i][j]);
                }
            }
        }
        for(int i = 1; i <= n; i++) {
            MM.addedge(S, i + n + 1, 1, 0);
            MM.addedge(i, T, 1, 0);
        }
        MM.addedge(S, 0 + n + 1, k, 0);
        int ans = MM.go();
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> n >> m >> k) run();
    	return 0;
    }
    
  • 相关阅读:
    将SpringBoot应用Docker化并部署到SAP云平台
    另一种办法直接在宿主机上的文件夹内查看Docker镜像运行的日志文件
    Dockerfile里的VOLUMES关键字
    Effective C++笔记(三):资源管理
    Denoise Autoencoder简单理解
    Visual Tracking with Fully Convolutional Networks
    Effective C++笔记(二):构造/析构/赋值运算
    effective c++读书笔记(一)
    Robust Online Visual Tracking with a Single Convolutional Neural Network
    C++卷积神经网络实例(一)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11770575.html
Copyright © 2011-2022 走看看