网络流问题——最大带权闭合路径 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 F. Clever King

例题 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 F. Clever King

In order to increase the happiness index of people’s lives, King Y has decided to develop the manufacturing industry vigorously. There are total n kinds of products that King can choose to produce, different products can improve the happiness index of poeple’s lives in different degrees, of course, the production of goods needs raw materials, different products need different ore or other products as raw materials. There are total m mines, and each mine can exploit different ore, Therefore, there are m types of ores, the cost of each mining for each mine is different, king Y want to maximize the income, the calculation method of income is:∑increased happiness index - ∑mining costs.
If you choose to exploit a mine, there will be an unlimited number of this kind of ore. What’s more, if you produce one product, the happiness index will definitely increase, no matter how many you produce.

Input

The first line of the input has an integer T(1<=T<=50), which represents the number of test cases.
In each test case, the first line of the input contains two integers n(1<=n<=200)–the number of the products and m(1<=m<=200)–the number of mines. The second line contains n integers, val[i] indicates the happiness index that number i product can increase. The third line contains m integers, cost[i] indicates the mining cost of number i mine. The next n lines, each line describes the type of raw material needed for the number i product, in each line, the first two integers n1(1<=n1<=m)–the number of ores that this product needs, n2(1<=n2<=n)–the number of products that this product needs, the next n1 + n2 integers indicate the id of ore and product that this product needs. it guarantees that ∑n1+∑n2<=2000.

Output

Each test case output an integer that indicates the maximum value ∑val[i]-∑cost[i].

Sample Input

2
3 3
600 200 400
100 200 300
1 2 1 2 3
1 0 2
1 0 3
3 4
600 400 200
100 200 300 1000
2 1 1 2 3
1 0 1
1 0 1

Sample Output

600
900

割问题(来源:胡伯涛《最小割模型在信息学竞赛中的应用》)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

最大带权闭合路径问题(来源:胡伯涛《最小割模型在信息学竞赛中的应用》)

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
总结下来就是:最大带权闭合路径等于所有正的权值之和减去最小割(即最大流)

本题分析

这样一看,本题的就是一个裸的最大带权闭合路径。新建一个起始节点与所有产品相连接(生产该产品带来的正值),容量为该权值
再新建一个终节点与所有矿物相连(开采矿物的消耗),容量为该权值
生产的依赖关系转化为边的相连接,容量为正无穷
根据上面的定义,本题的答案就是:
生产该产品带来的正值 - 最小割(即最大流)

样例实现代码

/*
ZhangBinjie@Penguin
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#define maxn 1000+2
#define inf 0x7f7f7f7f
using namespace std;

struct Edge {
    int from, to;
    long long cap, flow;
    Edge(int u, int v, int c, int f) :from(u), to(v), cap(c), flow(f) {}
};

struct EDmondsKarp {
    int n, m;
    vector<Edge>edges;
    vector<int>G[maxn];
    long long a[maxn];
    int p[maxn];

    void init() {
        for (int i = 0; i<maxn; ++i)
            G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, long long cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    long long Maxflow(int s, int t) {
        long long flow = 0;
        for (;;) {
            memset(a, 0, sizeof(a));
            queue<int>Q;
            Q.push(s);
            a[s] = inf;
            while (!Q.empty()) {
                int x = Q.front();
                Q.pop();
                for (int i = 0; i<G[x].size(); i++) {
                    Edge& e = edges[G[x][i]];
                    if (!a[e.to] && e.cap>e.flow) {
                        p[e.to] = G[x][i];
                        a[e.to] = min(a[x], e.cap - e.flow);
                        Q.push(e.to);
                    }
                }
                if (a[t])
                    break;
            }
            if (!a[t])
                break;
            for (int u = t; u != s; u = edges[p[u]].from) {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
};

int main() {
    int T;
    int n, m, a, b, t;
    long long sum;
    long long mincut;
    EDmondsKarp e;
    cin >> T;
    while (T--) {
        sum = 0;
        e.init();
        cin >> n >> m;
        for (int i = 1; i <= n; ++i) {
            cin >> t;
            e.AddEdge(0, i, t);
            sum += t;
        }
        for (int i = 1; i <= m; ++i) {
            cin >> t;
            e.AddEdge(i + 500, 1000, t);
        }
        for (int i = 1; i <= n; ++i) {
            cin >> a >> b;
            for (int j = 0; j<a; ++j) {
                cin >> t;
                e.AddEdge(i, t + 500, inf);
            }
            for (int j = 0; j<b; ++j) {
                cin >> t;
                e.AddEdge(i, t, inf);
            }
        }
        mincut = sum - e.Maxflow(0, 1000);
        cout << mincut << endl;
    }

    return 0;
}

结果

这里写图片描述

卸载最后

模板来源是刘汝佳书上的模板。
注意相关地方改成 long long
经测试,浙大的最大流模板会超时
吉林大学的模板待测试

猜你喜欢

转载自blog.csdn.net/HZEUHJEJNJ/article/details/80090766