POJ2987-Firing

来源:互联网 发布:spring boot 端口 编辑:程序博客网 时间:2024/06/06 13:42

利用Dinic求最小割,求最大权闭合图。
其中最大权=正权和-最小割,即最大裁员收益。
在求出最小割之后,遍历搜索残余网络的顶点个数即可求出裁员的个数。

数据太大需要用long long。
计算残余网络的顶点个数时要去掉源点。

#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <algorithm>using namespace std;const int maxn = 5000 + 5;const long long INF = 10e7 +5;int b[maxn];struct edge {    int to, cap, rev;};vector<edge> G[maxn];int level[maxn];int iter[maxn];void add_edge(int from, int to, int cap) {    G[from].push_back((edge){to, cap, G[to].size()});    G[to].push_back((edge){from, 0, G[from].size() - 1});}void bfs(int s) {    memset(level, -1, sizeof(level));    queue<int> q;    level[s] = 0;    q.push(s);    while (!q.empty()) {        int v = q.front();        q.pop();        for (int i = 0; i < G[v].size(); i++) {            edge &e = G[v][i];            if (e.cap > 0 && level[e.to] < 0) {                level[e.to] = level[v] + 1;                q.push(e.to);            }        }    }}int dfs(int v, int t, int f) {    if (v == t) {        return f;    }    for (int &i = iter[v]; i < G[v].size(); i++) {        edge &e = G[v][i];        if (e.cap > 0 && level[v] < level[e.to]) {            int d = dfs(e.to, t, min(f, e.cap));            if (d > 0) {                e.cap -= d;                G[e.to][e.rev].cap += d;                return d;            }        }    }    return 0;}long long Dinic(int s, int t) {    long long flow = 0;    for ( ; ; ) {        bfs(s);        if (level[t] < 0) {            return flow;        }        memset(iter, 0, sizeof(iter));        int f;        while ((f = dfs(s, t, INF)) > 0) {            flow += f;        }    }}//搜索残余网络bool vis[maxn];int cnt = -1;void Dfs_residual(int v, int t) {    if (v == t) {        return;    }    cnt++;    vis[v] = true;    for (int i = 0; i < G[v].size(); i++) {        edge &e = G[v][i];        if (e.cap > 0 && !vis[e.to]) {            Dfs_residual(e.to, t);        }    }}int main() {    int n, m;    scanf("%d%d", &n, &m);    int s = n, t = s + 1;    long long sum = 0;    for (int i = 0; i < n; i++) {        scanf("%d", &b[i]);        if (b[i] > 0) {            add_edge(s, i, b[i]);            sum += b[i];        } else {            add_edge(i, t, -b[i]);        }    }    for (int i = 0; i < m; i++) {        int from, to;        scanf("%d%d", &from, &to);        add_edge(from-1, to-1, INF);    }    long long ans = sum - Dinic(s, t);    Dfs_residual(s, t);    printf("%d %lld\n", cnt, ans);    return 0;}
0 0
原创粉丝点击