LOJ2471/LG4363 「九省联考 2018」一双木棋
问题描述
菲菲和牛牛在一块 \(n\) 行 \(m\) 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。
棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。
棋盘的每个格子上,都写有两个非负整数,从上到下第 \(i\) 行中从左到右第 \(j\) 列的格子上的两个整数记作 \(A_{i,j}\)、\(B_{i,j}\)。在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的 \(A_{i,j}\) 之和,牛牛的得分是所有有白棋的格子上的 \(B_{i,j}\) 的和。
菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何。
题解
vector 记录状态, map 记忆化
爆搜。
\(\texttt{Code}\)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10 + 3;
const int INF = 0x3f3f3f3f;
int n, m;
int a[maxn][maxn], b[maxn][maxn];
map < vector <int> , int> mp;
vector <int> h, tp;
void Init(void) {
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]);
}
void Preprocess(void) {
for(int i = 1; i <= n; i++) tp.push_back(m);
mp[tp] = 0;
for(int i = 1; i <= n; i++) h.push_back(0);
}
int dfs(int dep) {
if(mp.find(h) != mp.end()) return mp[h];
int ans;
if(dep == 1) ans = -INF;
else ans = INF;
for(int i = 0; i < n; i++) {
if((i == 0 || h[i - 1] > h[i]) && h[i] < m) {
h[i]++;
if(dep == 1) {
int p = dfs(0);
ans = max(ans, p + a[i + 1][h[i]]);
}
else {
int p = dfs(1);
ans = min(ans, p - b[i + 1][h[i]]);
}
h[i]--;
}
}
mp[h] = ans;
return ans;
}
void Work(void) {
Preprocess();
printf("%d\n", dfs(1));
}
int main(void) {
Init();
Work();
return 0;
}