bzoj 4485 [Jsoi2015] minimum cutting of enclosure

Posted by mjurmann on Tue, 31 Dec 2019 23:14:00 +0100

Problem surface

Title gate

solution

It is easy to think of the minimum cut of the model

  • It can be found that this is obviously a minimal cut model
  • It is advisable to connect all the products sold to the first person with SS, and those sold to the other person with TT. The capacity is the price in each cell
  • Then connect the adjacent grids to each other. The capacity is the cost of building a wall between two grids. Then use all the prices - the minimum cut is the answer
  • Considering the correctness of this algorithm, it is obvious that a point is either not taken, or it must be assigned to SS set or TT set. When building the fence, we ensure that the points of SS set and TT set are not in the same connected block, because we are seeking the minimum cut
  • Although it seems that the number of points is 400 × 400400 × 400, this problem can be easily passed by dinic algorithm and current arc optimization

Code

#include <bits/stdc++.h>
#define N 410
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Edge {
    int next, num, c;
} e[N * N * 16];
int n, m, s, t, cnt, l[N * N], cur[N * N];
int calc(int x, int y) {return (x - 1) * m + y;}
void add(int x, int y, int c) {
    e[++cnt] = (Edge) {e[x].next, y, c};
    e[x].next = cnt;
}
void Add(int x, int y, int c) {
    add(x, y, c), add(y, x, 0);
}
bool bfs(int s) {
    for (int i = 1; i <= t; i++) l[i] = -1;
    queue <int> q; q.push(s);
    while (!q.empty()) {
        int x = q.front(); q.pop();
        for (int p = e[x].next; p; p = e[p].next) {
            int k = e[p].num, c = e[p].c;
            if (c && l[k] == -1)
                q.push(k), l[k] = l[x] + 1;
        }
    }
    return l[t] != -1;
}
int dfs(int x, int lim) {
    if (x == t) return lim;
    int used = 0;
    for (int p = cur[x]; p; p = e[p].next) {
        int k = e[p].num, c = e[p].c;
        if (c && l[k] == l[x] + 1) {
            int w = dfs(k, min(c, lim - used));
            e[p].c -= w, e[p ^ 1].c += w, used += w;
            if (e[p].c) cur[x] = p;
            if (lim == used) return lim;
        }
    }
    if (!used) l[x] = -1; return used;
}
int dinic() {
    int ret = 0;
    while (bfs(s)) {
        for (int i = 0; i <= t; i++) cur[i] = e[i].next;
        ret += dfs(s, INT_MAX);
    }
    return ret;
}
int main() {
    read(n), read(m);
    s = 0, t = cnt = n * m + 1;
    if (cnt % 2 == 0) cnt++;
    int ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            int x; read(x); ans += abs(x);
            if (x < 0) Add(s, calc(i, j), -x);
                else if (x > 0) Add(calc(i, j), t, x);
        }
    for (int i = 1; i < n; i++)
        for (int j = 1; j <= m; j++) {
            int x; read(x);
            Add(calc(i, j), calc(i + 1, j), x);
            Add(calc(i + 1, j), calc(i, j), x);
        }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j < m; j++) {
            int x; read(x);
            Add(calc(i, j), calc(i, j + 1), x);
            Add(calc(i, j + 1), calc(i, j), x);
        }
    cout << ans - dinic() << "\n";
    return 0;
}