Description:
地图是个矩形的网格。
可以花费一定金钱在一些格子投资。
被投资的格子或者四连通的格子都被投资的话,我就可以获得该格子的收益。
利益最大化是作为商人的基本准则,但这是计算机的任务,拜托您了。
题解:
这个“或”非常骚,骚到我不会做。
考虑最小割。
那么答案=总利益-割掉的不要的利益-割掉的要的代价
显然对于一个点来说,利益和代价要连在一起,使两者割其一即可。
再考虑或,即一个点四连通的格子都割代价时,这个点的利益可以不割,
于是想到这样建:
对于点x,设y是其一个四连通的点。
则
s->y :y代价
y->y’:y利益
y->x:inf
y’->x’:inf
x->x’:利益
x’->T:代价
黑白染色最大流即可。
Code:
#include<cstdio>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 25, M = 1e6 + 5, inf = 1 << 30;
int move[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
char s[N];
int n, m, num[N][N], S, T, ans;
int final[M], next[M], to[M], r[M], tot = 1;
void link(int x, int y, int z) {
next[++ tot] = final[x], to[tot] = y, r[tot] = z, final[x] = tot;
next[++ tot] = final[y], to[tot] = x, r[tot] = 0, final[y] = tot;
}
int va(int c) {
if(c >= '0' && c <= '9') return c - '0';
if(c >= 'a' && c <= 'z') return 10 + c - 'a';
return 36 + c - 'A';
}
int cur[M], d[M], co[M];
int dg(int x, int flow) {
if(x == T) return flow;
int use = 0;
for(int i = cur[x]; i; i = next[i], cur[x] = i) {
int y = to[i];
if(d[y] + 1 == d[x] && r[i]) {
int tmp = dg(y, min(flow - use, r[i]));
r[i] -= tmp, r[i ^ 1] += tmp, use += tmp;
if(use == flow) return use;
}
}
cur[x] = final[x];
if(!(-- co[d[x]])) d[S] = T;
++ co[++ d[x]];
return use;
}
int main() {
scanf("%d %d", &n, &m);
fo(i, 1, n) fo(j, 1, m) num[i][j] = (i - 1) * m + j;
S = n * m * 2 + 1; T = S + 1;
fo(i, 1, n) {
scanf("%s", s + 1);
fo(j, 1, m) {
int z = va(s[j]);
if(i + j & 1)
link(S, num[i][j], z); else
link(num[i][j], T, z);
}
}
fo(i, 1, n) {
scanf("%s", s + 1);
fo(j, 1, m) {
int z = va(s[j]); ans += z;
if(i + j & 1)
link(num[i][j], num[i][j] + n * m, z); else
link(num[i][j] + n * m, num[i][j], z);
}
}
fo(i, 1, n) fo(j, 1, m) if(i + j & 1) {
fo(k, 0, 3) {
int x = i + move[k][0], y = j + move[k][1];
if(x > 0 && y > 0 && x <= n && y <= m) {
link(num[i][j], num[x][y] + n * m, inf);
link(num[i][j] + n * m, num[x][y], inf);
}
}
}
co[0] = T;
for(; d[S] < T;) ans -= dg(S, inf);
printf("%d", ans);
}