HDU 4971 A simple brute force problem.(最大权闭合)

来源:互联网 发布:伪装者于曼丽知乎 编辑:程序博客网 时间:2024/05/16 12:47

题目大意:有N个工程,完成一个工程获利pi. M个技术问题,解决一个技术问题需要花费ci
现在给出每个工程需要解决的技术问题,和解决一个技术问题前还需要解决哪些技术问题
问最大获利是多少

解题思路:最大权闭合的题目,构图的话
正权的话肯定是完成一个工程的获利,负权的话就是解决每个问题的费用了
接着是连边,可以画出图,他所需要的前置条件其实就是它所指向的点,这样就可以得到一张有向图了,有了有向图了,就可以建图了
具体的理论详见胡伯涛:算法合集之《最小割模型在信息学竞赛中的应用》

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>using namespace std;const int MAXNODE = 210;const int MAXEDGE = 100010;typedef int Type;const Type INF = 0x3f3f3f3f;struct Edge {    int u, v, next;    Type cap, flow;    Edge() {}    Edge(int u, int v, Type cap, Type flow, int next): u(u), v(v), cap(cap), flow(flow), next(next) {}};struct ISAP {    int n, m, s, t;    Edge edges[MAXEDGE];    int head[MAXNODE], p[MAXNODE], num[MAXNODE], cur[MAXNODE], d[MAXNODE];    bool vis[MAXNODE];    void init(int n) {        this->n = n;        memset(head, -1, sizeof(head));        m = 0;    }    void AddEdge(int u, int v, Type cap) {        edges[m] = Edge(u, v, cap, 0, head[u]);        head[u] = m++;        edges[m] = Edge(v, u, 0, 0, head[v]);        head[v] = m++;    }    bool BFS() {        memset(vis, 0, sizeof(vis));        queue<int> Q;        for (int i = 0; i < n; i++)            d[i] = INF;        d[t] = 0;        vis[t] = 1;        Q.push(t);        while (!Q.empty()) {            int u = Q.front(); Q.pop();            for (int i = head[u]; ~i; i = edges[i].next) {                Edge &e = edges[i ^ 1];                if (!vis[e.u] && e.cap > e.flow) {                    vis[e.u] = true;                    d[e.u] = d[u] + 1;                    Q.push(e.u);                }            }        }        return vis[s];    }    Type Augment() {        int u = t;        Type flow = INF;        while (u != s) {            Edge &e = edges[p[u]];            flow = min(flow, e.cap - e.flow);            u = edges[p[u]].u;        }        u = t;        while (u != s) {            edges[p[u]].flow += flow;            edges[p[u] ^ 1].flow -= flow;            u = edges[p[u]].u;        }        return flow;    }    Type Maxflow(int s, int t) {        this->s = s; this->t = t;        Type flow = 0;        BFS();        //如果s-->t走不通        if (d[s] >= n)            return 0;        memset(num, 0, sizeof(num));        for (int i = 0; i < n; i++)            cur[i] = head[i];        for (int i = 0; i < n; i++)            if (d[i] < INF)                 num[d[i]]++;        int u = s;        while (d[s] < n) {            if (u == t) {                flow += Augment();                u = s;            }            bool ok = false;//纪录是否找到了下一个点            for (int i = cur[u]; ~i; i = edges[i].next) {                Edge &e = edges[i];                if (e.cap > e.flow && d[u] == d[e.v] + 1) {                    ok = true;                    p[e.v] = i;//点v由第i条边增广得到                    cur[u] = i;//尝试到第i条边                    u = e.v;                    break;                }            }            //如果没找到下一个点,表示u到t的最短路要变长了,或者没路可走了            if (!ok) {                //找寻u到下一个点的最短路                int Min = n - 1;                for (int i = head[u]; ~i; i = edges[i].next) {                    Edge &e = edges[i];                    if (e.cap > e.flow)                        Min = min(Min, d[e.v]);                }                if (--num[d[u]] == 0)//GAP优化                    break;                num[d[u] = Min + 1]++;                cur[u] = head[u];                //返回前一个点,因为该点的最短距离已经变了                if (u != s)                    u = edges[p[u]].u;            }        }        return flow;    }}isap;int n, m, source, sink;int Sum, cas = 1;void init() {    scanf("%d%d", &n, &m);    source = 0, sink = n + m + 1;    isap.init(sink + 1);    Sum = 0;    int c, k;    for (int i = 1; i <= n; i++) {        scanf("%d", &c);        isap.AddEdge(source, i, c);        Sum += c;    }    for (int j = 1; j <= m; j++) {        scanf("%d", &c);        isap.AddEdge(j + n, sink, c);    }    for (int i = 1; i <= n; i++) {        scanf("%d", &k);        for (int j = 1; j <= k; j++) {            scanf("%d", &c);            isap.AddEdge(i, n + c + 1, INF);        }    }    for (int i = 1; i <= m; i++) {        for (int j = 1; j <= m; j++) {            scanf("%d", &c);            if (c) isap.AddEdge(n + i, n + j, INF);        }    }    int maxflow = isap.Maxflow(source, sink);    printf("Case #%d: %d\n", cas++, Sum - maxflow);}int main() {    int test;    scanf("%d", &test);    while (test--) {        init();    }    return 0;}
0 0
原创粉丝点击