【雅礼联考DAY02】Revolution

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);
}

猜你喜欢

转载自blog.csdn.net/cold_chair/article/details/81047766
今日推荐