POJ 2987【最大权闭合图】

题意:n(0 < n ≤ 5000)个人,m(0 ≤ m ≤ 60000)个上下级关系,炒一个人可以获得收益或者损失bi (|bi| ≤ 10 ^ 7, 1 ≤ i ≤ n),炒一个人会把他的所有下级一起炒掉,问怎样炒人使收益最大,输出最大收益和最少炒人的数量。

明显的最大权闭包图的条件。求一次最小割即可。对于要求最少的炒人数,也就是说我们选哪个闭合图会使得总收益最大。最小割中的S集合=s交V1,该V1即为所求。
因此我们求完最小割以后用dfs从s开始遍历,能走到的点都为V1中的点。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
#define MAX 5100
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

int ss, tt;
int kase;
int sum;
int n, m;
int cont;
int vis[MAX];
int head[MAX];
int divv[MAX];
int cur[MAX];
int cnt;
ll postive;
struct edge {
    int from, to, next;
    ll w;

}e[500000];

void add(int u, int v, int w) {
    e[cont].from = u;
    e[cont].to = v;
    e[cont].w = w;
    e[cont].next = head[u];
    head[u] = cont++;
}



int makediv() {
    memset(divv, 0, sizeof(divv));
    divv[ss] = 1;
    queue<int> Q;
    Q.push(ss);
    while (!Q.empty()) {
        int u = Q.front();
        if (u == tt)
            return 1;
        Q.pop();
        for (int i = head[u]; i != -1; i = e[i].next) {
            ll w = e[i].w;
            int v = e[i].to;
            if (divv[v] == 0 && w) {
                divv[v] = divv[u] + 1;
                Q.push(v);
            }
        }

    }
    return 0;

}

ll DFS(int u, ll maxflow, int tt) {
    if (u == tt)
        return maxflow;
    int ret = 0;
    for (int &i = cur[u]; i != -1; i = e[i].next) {
        int v = e[i].to;
        ll w = e[i].w;
        if (divv[v] == divv[u] + 1 && w) {
            int f = DFS(v, min(maxflow - ret, w), tt);
            e[i].w -= f;
            e[i ^ 1].w += f;
            ret += f;
            if (ret == maxflow)
                return ret;

        }
    }
    return ret;
}

void dfs(int s) {
    vis[s] = 1;
    for (int i = head[s]; i != -1; i = e[i].next) {
        int v = e[i].to;
        ll w = e[i].w;
        if (!vis[v] && w) {
            dfs(v);
            cnt++;
        }
    }

}
void Dinic() {
    ll ans = 0;

    while (makediv() == 1) {
        memcpy(cur, head, sizeof(head));
        ans += DFS(ss, INF, tt);
    }
    dfs(ss);
    printf("%d %I64d\n", cnt, postive - ans);
}

int main(void) {
    while (~scanf("%d%d", &n, &m)) {
        memset(vis, 0, sizeof(vis));
        cnt = 0;
        postive = 0;
        cont = 0;
        memset(head, -1, sizeof(head));
        ss = 0;
        tt = n + 1;
        ll w, u, v;
        for (int i = 1; i <= n; i++) {
            scanf("%I64d", &w);
            if (w > 0) {
                add(ss, i, w);
                add(i, ss, 0);
                postive += w;
            }
            if (w < 0) {
                add(i, tt, -w);
                add(tt, i, 0);
            }
        }
        for (int i = 1; i <= m; i++) {
            scanf("%I64d%I64d", &u, &v);
            add(u, v, INF);
            add(v, u, 0);
        }
        Dinic();

    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/tennant/p/8983465.html