Description
菲菲和牛牛在一块n行m列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。棋盘的每个格子上,都写有两个非负整数,从上到下第i行中从左到右第j列的格子上的两个整数记作Aij、Bij。在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所有有白棋的格子上的Bij的和。
菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何。
Solution
由于每一行的棋子不能超过上一行,所以状态数非常少,大概是十万级别的,考虑dp。
对于每一个状态我们哈希一下,存在map
或hash_table
里面,直接转移就行了。
Code
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define SZ(a) ((int)(a.size()))
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define INF (0x3f3f3f3f)
typedef long long LL;
typedef pair<int, int> PII;
template<typename T> bool chkmin(T& a, T b) { return a > b ? a = b, 1 : 0; }
template<typename T> bool chkmax(T& a, T b) { return a < b ? a = b, 1 : 0; }
inline int read()
{
register int _ = 0, __ = 1; register char c_;
for (c_ = getchar(); !isdigit(c_); c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; isdigit(c_); c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ - 48);
return _ * __;
}
const int maxn = 13;
struct Data
{
int a[maxn];
}a;
cc_hash_table<LL, int> dp;
int A[maxn][maxn], B[maxn][maxn], n, m;
queue<Data> q;
inline LL Hash(Data a)
{
LL hash = 0;
For(i, 1, n) (hash *= 11ll) += a.a[i];
return hash;
}
int dfs(Data a)
{
int t = Hash(a);
if (dp[t]) return dp[t];
int tmp, cnt = 0, mark = 1;
For(i, 1, n) {
cnt += (a.a[i] & 1);
if (a.a[i] != m) mark = 0;
}
if (mark) return 0;
cnt &= 1;
cnt ^= 1;
if (cnt) tmp = -INF; else tmp = INF;
For(i, 1, n)
{
if (a.a[i] + 1 <= a.a[i - 1])
{
++ a.a[i];
if (!cnt) chkmin(tmp, dfs(a) - B[i][a.a[i]]);
else chkmax(tmp, dfs(a) + A[i][a.a[i]]);
-- a.a[i];
}
}
//For(i, 1, n) cout << a.a[i] << ' ';
//cout << tmp << endl;
dp[t] = tmp;
return tmp;
}
int main()
{
n = read(), m = read();
For(i, 1, n) For(j, 1, m) A[i][j] = read();
For(i, 1, n) For(j, 1, m) B[i][j] = read();
For(i, 1, n) a.a[i] = 0;
a.a[0] = m;
printf("%d\n", dfs(a));
return 0;
}
//风急天高猿啸哀,渚清沙白鸟飞回。
// -- 杜甫《登高》