Description:
题解:
分成三类点:
(i+j)是奇数的,也就是需要去覆盖的点。
(i+j)是偶数,且i是奇数的点。
(i+j)是偶数,且i是偶数的点。
然后你就得到(i+j)是奇数的点一定是由相邻的(i+j)是偶数且i奇偶性不同的两个点覆盖,
然后就可以建图流了。
注意是最大费用可行流,用SPFA求最长路。
由于每次的增广路流量一定是1,所以只要找不超过m条增广路就行了。
Code:
#include<cstdio>
#define ll long long
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 55, M = 1e6;
int move[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int n, m, P, x, y, v[N][N], bx[N][N];
int num[N][N], td, S, T;
int final[M], to[M], next[M], r[M], tot = 1;
int d[M * 10], bz[M], la[M]; ll w[M], dis[M], ans, rans;
void link(int x, int y, int z, ll u) {
next[++ tot] = final[x], to[tot] = y, r[tot] = z, w[tot] = u, final[x] = tot;
next[++ tot] = final[y], to[tot] = x, r[tot] = 0, w[tot] = -u, final[y] = tot;
}
int spfa() {
fo(i, 1, td) dis[i] = -1e18;
dis[S] = 0; d[d[0] = 1] = S; bz[S] = 1;
fo(i, 1, d[0]) {
int x = d[i];
for(int j = final[x]; j; j = next[j])
if(r[j] && dis[x] + w[j] > dis[to[j]]) {
dis[to[j]] = dis[x] + w[j]; la[to[j]] = j;
if(!bz[to[j]]) bz[to[j]] = 1, d[++ d[0]] = to[j];
}
bz[x] = 0;
}
return dis[T] > 0;
}
void gg() {
int x = T, minh = 1e9;
while(x != S) minh = min(minh, r[la[x]]), x = to[la[x] ^ 1];
x = T;
while(x != S) ans -= minh * w[la[x]], r[la[x]] -= minh, r[la[x] ^ 1] += minh, x = to[la[x] ^ 1];
}
int main() {
freopen("marshland.in", "r", stdin);
freopen("marshland.out", "w", stdout);
scanf("%d %d %d", &n, &m, &P);
fo(i, 1, n) fo(j, 1, n) {
scanf("%d", &v[i][j]);
num[i][j] = ++ td;
}
fo(i, 1, P) {
scanf("%d %d", &x, &y);
bx[x][y] = 1;
}
S = ++ td; T = ++ td;
fo(i, 1, n) fo(j, 1, n) {
if(bx[i][j]) continue;
if(i + j & 1) {
link(num[i][j], ++ td, 1, v[i][j]); ans += v[i][j];
fo(k, 0, 3) {
int x = i + move[k][0], y = j + move[k][1];
if(x && y && x <= n && y <= n && !bx[x][y]) {
if(x & 1) link(num[x][y], num[i][j], 1, 0); else link(td, num[x][y], 1, 0);
}
}
} else
if(i & 1) {
link(S, num[i][j], 1, 0);
} else {
link(num[i][j], T, 1, 0);
}
}
while(rans < m && spfa()) gg(), rans ++;
printf("%lld", ans);
}