题目链接:
题目分析:
网络流
考虑先将棋盘黑白染色变成二分图,这样使得每个格子有公共边的其他格子和它自己都是异色的,然后把它向其他四个方向的点连一下边,边容量\(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;
}