zoukankan      html  css  js  c++  java
  • 数字梯形问题(费用流,最大权不相交路径,网络流24题)

    题意

    思路

    • 第一问

    (m)条路径中,每个点只能使用(1)次,每条边也只能使用(1)次,获益为经过点的点权和。

    这里的费用不是边的费用,而是点的费用,因此可以采用拆点的技巧,即拆成一个入点和一个出点,入点与出点连边,容量是(1)(因为每个点只能使用一次),费用是点权。

    设立虚拟源点(S),与第一行的(m)个数字的入点连边,容量是(1)(因为每个点只能使用一次),费用是(0)(费用只能出现在入点指向出点的边上)。

    设立虚拟汇点(T),最后一行的数字与(T)的出点连边,容量是(1),费用是(0)

    每个点的出点与之斜下方两点的入点连边,容量是(1),费用是(0)

    跑最大费用流即可。

    • 第二问

    每个点的使用次数不限,但是值得注意的是第一行的点只能使用(1)次,原因是一开始每个点只使用了一次,并且中间过程中不会再到达第一行的数字。每条边还是只能使用(1)次。

    因此,与第一问相比,需要修改的地方是,入点连向出点的边,容量改成(infty)。最后一行数字的出点,指向(T)的边的容量改成(infty)

    • 第三问

    每个点的使用次数不限,第一行的点只能使用(1)次,每条边也可以使用无限次。

    因此,与第二问相比,需要修改的地方是,每个点的出点指向斜下方两点的入点的容量改成(infty)

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int N = 1200, M = 4000, inf = 1e8;
    
    int n, m, S, T;
    int h[N], e[M], ne[M], f[M], w[M], idx;
    int pre[N], d[N], incf[N];
    bool st[N];
    int cost[25][25], id[25][25];
    
    void add(int a, int b, int c, int d)
    {
        e[idx] = b, f[idx] = c, w[idx] = d, ne[idx] = h[a], h[a] = idx ++;
        e[idx] = a, f[idx] = 0, w[idx] = -d, ne[idx] = h[b], h[b] = idx ++;
    }
    
    bool spfa()
    {
        memset(d, 0x3f, sizeof(d));
        memset(incf, 0, sizeof(incf));
        queue<int> que;
        que.push(S);
        d[S] = 0, incf[S] = inf;
        st[S] = true;
        while(que.size()) {
            int t = que.front();
            que.pop();
            st[t] = false;
            for(int i = h[t]; ~i; i = ne[i]) {
                int ver = e[i];
                if(d[ver] > d[t] + w[i] && f[i]) {
                    d[ver] = d[t] + w[i];
                    pre[ver] = i;
                    incf[ver] = min(incf[t], f[i]);
                    if(!st[ver]) {
                        que.push(ver);
                        st[ver] = false;
                    }
                }
            }
        }
        return incf[T] > 0;
    }
    
    int EK()
    {
        int cost = 0;
        while(spfa()) {
            int t = incf[T];
            cost += t * d[T];
            for(int i = T; i != S; i = e[pre[i] ^ 1]) {
                f[pre[i]] -= t;
                f[pre[i] ^ 1] += t;
            }
        }
        return cost;
    }
    
    int main()
    {
        scanf("%d%d", &m, &n);
        int cnt = 0;
        S = ++ cnt;
        T = ++ cnt;
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m + i - 1; j ++) {
                scanf("%d", &cost[i][j]);
                id[i][j] = ++ cnt;
            }
        }
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m + i - 1; j ++) {
                int in = id[i][j] * 2, out = in + 1;
                add(in, out, 1, -cost[i][j]);
                if(i == 1) add(S, in, 1, 0);
                if(i == n) add(out, T, 1, 0);
                if(i < n) {
                    add(out, id[i + 1][j] * 2, 1, 0);
                    add(out, id[i + 1][j + 1] * 2, 1, 0);
                }
            }
        }
        printf("%d
    ", -EK());
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m + i - 1; j ++) {
                int in = id[i][j] * 2, out = in + 1;
                add(in, out, inf, -cost[i][j]);
                if(i == 1) add(S, in, 1, 0);
                if(i == n) add(out, T, inf, 0);
                if(i < n) {
                    add(out, id[i + 1][j] * 2, 1, 0);
                    add(out, id[i + 1][j + 1] * 2, 1, 0);
                }
            }
        }
        printf("%d
    ", -EK());
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= m + i - 1; j ++) {
                int in = id[i][j] * 2, out = in + 1;
                add(in, out, inf, -cost[i][j]);
                if(i == 1) add(S, in, 1, 0);
                if(i == n) add(out, T, inf, 0);
                if(i < n) {
                    add(out, id[i + 1][j] * 2, inf, 0);
                    add(out, id[i + 1][j + 1] * 2, inf, 0);
                }
            }
        }
        printf("%d
    ", -EK());
        return 0;
    }
    
  • 相关阅读:
    Codechef EDGEST 树套树 树状数组 线段树 LCA 卡常
    BZOJ4319 cerc2008 Suffix reconstruction 字符串 SA
    Codechef STMINCUT S-T Mincut (CodeChef May Challenge 2018) kruskal
    Codeforces 316G3 Good Substrings 字符串 SAM
    Codechef CHSIGN Change the Signs(May Challenge 2018) 动态规划
    BZOJ1396 识别子串 字符串 SAM 线段树
    CodeForces 516C Drazil and Park 线段树
    CodeForces 516B Drazil and Tiles 其他
    CodeForces 516A Drazil and Factorial 动态规划
    SPOJ LCS2
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14413304.html
Copyright © 2011-2022 走看看