Address
https://www.lydsy.com/JudgeOnline/problem.php?id=5248
Solution
容易想到 dp :
表示当前棋子的状态为
,从状态
到棋盘被摆满的过程中,
的最大值。
考虑如何存下这个状态。
看到落子的规则,可以发现任何时候棋盘都满足:
(1)有棋子的行一定是前面的几行。
(2)在每行内,有棋子的格子一定是前面的几格。
(3)一行内的棋子个数随行号单调不增。
所以用 map 存转移,合法的
是可以承受的。
为偶数时,转移:
否则 为奇数:
为枚举的行号。
表示第 行的最后一个棋子所在列号。
表示在状态 第 行第 列放棋子达到的状态。
Code
#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll; const int N = 11, INF = 0x3f3f3f3f;
int n, m, a[N][N], b[N][N], suma[N][N], sumb[N][N];
struct cyx {
int x[N];
friend inline bool operator == (cyx a, cyx b) {
int i; For (i, 1, n) if (a.x[i] != b.x[i]) return 0;
return 1;
}
} emp, eds;
int orz(cyx state) {
int i, res = 0; For (i, 1, n) res += state.x[i];
return res & 1;
}
ll encode(cyx state) {
int i; ll res = 0;
For (i, 1, n) (res *= m) += state.x[i] - 1;
return res;
}
map<ll, int> f, w;
int dp(cyx state) {
ll sta = encode(state);
if (state == eds) return w[sta] = 1, f[sta] = 0;
if (w[sta]) return f[sta];
int i, res = -INF, p = orz(state);
For (i, 1, n)
if ((i == 1 || state.x[i] < state.x[i - 1])
&& state.x[i] < m) {
cyx ns = state; ns.x[i]++;
res = max(res, (p ? b[i][ns.x[i]]
: a[i][ns.x[i]]) - dp(ns));
}
return w[sta] = 1, f[sta] = res;
}
int main() {
int i, j; 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) Rof (j, m, 1) suma[i][j] = suma[i][j + 1] + a[i][j];
For (i, 1, n) Rof (j, m, 1) sumb[i][j] = sumb[i][j + 1] + b[i][j];
For (i, 1, n) eds.x[i] = m;
cout << dp(emp) << endl;
return 0;
}