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

Description

题库链接

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

(1leq n,mleq 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
", dfs(states, 1));
}
int main() {work(); return 0; }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8970881.html