[SDOI 2018] 一双木棋 chess

Description

题面

Solution

显然状态永远是阶梯状,设第 \(i\) 行的棋子数为 \(x_i\),则 \(\sum\limits_{i=2}^{n}x_i-x_{i-1}=m\),插板法算出状态数为 \(\binom{n+m}{n}\),直接记搜。

Code

#include <cstdio>
#include <tr1/unordered_map>

const int INF = 0x3f3f3f3f;
int n, m, a[11][11], b[11][11], s[11];
std::tr1::unordered_map<int,int> mp;

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
int min(int x, int y) {
    return x < y ? x : y;
}
int max(int x, int y) {
    return x > y ? x : y;
}
int hash() {
    int res = 0;
    for (int i = 1; i <= n; ++i) res = res * 11 + m - s[i];
    return res;
}
int dfs(int k) {
    int now = hash();
    if (now == 0) return 0;
    if (mp.count(now)) return mp[now];
    int res = k ? INF : -INF, tmp;
    for (int i = 1; i <= n; ++i)
        if (s[i] < m && (i == 1 || s[i-1] > s[i])) {
            ++s[i], tmp = dfs(k ^ 1);
            res = k ? min(res, tmp - b[i][s[i]]) : max(res, tmp + a[i][s[i]]);
            --s[i];
        }
    return (mp[now] = res);
}
int main() {
    n = read(), m = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) a[i][j] = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) b[i][j] = read();
    printf("%d\n", dfs(0));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10069163.html
今日推荐