[九省联考 2018]一双木棋chess

Description

题库链接

给出一个 $n\times m$ 的棋盘,棋盘的每个格子有两个权值 $A,B$ 。 Alice 和 Bob 轮流操作在棋盘上放棋子,一个格子能放棋子的前提条件是这个格子的左侧和上侧均放了棋子。对于 Alice 放棋子的格子,能获得该格子的 $A$ 的权值;对于 Bob 放棋子的格子,能获得该格子的 $B$ 的权值。 Alice 想最大化得分差, Bob 想最小化得分差,求最后得分差。

$1\leq n,m\leq 10$

Solution

比较简单啊,状压轮廓线记搜就好了。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 10+5;
const int SIZE = (1<<20)+5;

int n, m, a[N][N], b[N][N], bin[N<<1];
int f[SIZE], inf;

int dfs(int S, int who) {
    if (f[S] != -inf) return f[S];
    int ans = who ? -inf : inf;
    for (int i = 0, loc = 0; i < n+m; i++) {
        if (S&bin[i]) ++loc;
        if (S&bin[i+1] && !(S&bin[i])) {
            int t = dfs(S-bin[i+1]+bin[i], who^1);
            if (who == 1) ans = max(ans, t+a[n-i+loc][loc+1]);
            else ans = min(ans, t-b[n-i+loc][loc+1]);
        }
    }
    if (abs(ans) == inf) ans = 0; f[S] = ans;
    return f[S];
}
void work() {
    memset(f, 128, sizeof(f)); inf = -f[0];
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]);
    for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &b[i][j]);
    bin[0] = 1; for (int i = 1; i <= 21; i++) bin[i] = (bin[i-1]<<1);
    int states = 0;
    for (int i = 1; i <= m; i++) states |= bin[n-1+i];
    printf("%d\n", dfs(states, 1));
}
int main() {work(); return 0; }
posted @ 2018-04-29 14:31  NaVi_Awson  阅读(218)  评论(0编辑  收藏  举报