方格取数问题

Posted kma093

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方格取数问题相关的知识,希望对你有一定的参考价值。

题目链接:

点我

题目分析:

网络流
考虑先将棋盘黑白染色变成二分图,这样使得每个格子有公共边的其他格子和它自己都是异色的,然后把它向其他四个方向的点连一下边,边容量(INF)(S)连黑点,容量为权值,白点连(T),容量同理
于是问题转化为一个最小割问题

代码:

#include<bits/stdc++.h>
#define INF (1000000000 + 7)
#define N (100000 + 10)
using namespace std;
inline int read() {
    int cnt = 0, f= 1;char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
const int fx[5] = {0, 1, 0, -1, 0};
const int fy[5] = {0, 0, -1, 0, 1};
int m, n, s, t, first[N << 2], nxt[N << 2], to[N << 2], flow[N], tot = 1, dep[N], cnt[N], ans;
void add(int x, int y, int z) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;}
int Map[110][110];
queue <int> q;
void build () {
    for (register int i = 1; i <= m; ++i) 
        for (register int j = 1; j <= n; ++j) {
            if ((i + j) & 1) add(s, (i - 1) * n + j, Map[i][j]), add((i - 1) * n + j, s, 0);
            else add(t, (i - 1) * n + j, 0), add((i - 1) * n + j, t, Map[i][j]);
        }
    for (register int i = 1; i <= m; ++ i)
        for (register int j = 1; j <= n; ++j) {
            if ((i + j) & 1) {
                for (register int k = 1; k <= 4; ++k) {
                    int x = i + fx[k], y = j + fy[k];
                    if (x < 1 || y < 1 || x > m || y > n) continue;
                    add((i - 1) * n + j, (x - 1) * n + y, INF);
                    add((x - 1) * n + y, (i - 1) * n + j, 0);
                }
            }
        }
}
void bfs_(int t) {
    memset(dep, 0xff, sizeof dep);
    dep[t] = 0, cnt[0] = 1;
    q.push(t);
    while (!q.empty()) {
        int p = q.front(); q.pop();
        for (register int i = first[p]; i; i = nxt[i]) {
            int v = to[i];
            if (dep[v] == -1) {
                ++cnt[dep[v] = dep[p] + 1];
                q.push(v);
            }
        }
    }
}
int max_flow;
int dfs_(int p, int f) {
    if (p == t) {max_flow += f; return f;}
    int u = 0;
    for (register int i = first[p]; i; i = nxt[i]) {
        int v = to[i];
        if (flow[i] && dep[v] == dep[p] - 1) {
            int uu = dfs_(v, min(flow[i], f - u));
            if (uu) {
                flow[i] -= uu, flow[i ^ 1] += uu, u += uu;
            }
            if (u >= f) return u;
        }
    }
    if (!--cnt[dep[p]]) dep[s] = m * n + 3;
    ++cnt[++dep[p]];
    return u;
}
int main() {
    m = read(), n = read();
    s = m * n + 1, t = m * n + 2;
    for (register int i = 1; i <= m; ++i) 
        for (register int j = 1; j <= n; ++j) 
            Map[i][j] = read(), ans += Map[i][j];
    build();
    bfs_(t);
    while (dep[s] < m * n + 3) dfs_(s, INF);
    printf("%d", ans - max_flow);
    return 0;
}

以上是关于方格取数问题的主要内容,如果未能解决你的问题,请参考以下文章

方格取数问题 最小割

P2774 方格取数问题

网络流24题方格取数问题

P2774 方格取数问题 网络流

LuoguP2774 方格取数问题(最小割)

网络流24题9方格取数问题