[BZOJ5248][2018多省省队联测]一双木棋(状压dp)

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=5248

Solution

容易想到 dp :
f [ S ] 表示当前棋子的状态为 S ,从状态 S 到棋盘被摆满的过程中, 的最大值。
考虑如何存下这个状态。
看到落子的规则,可以发现任何时候棋盘都满足:
(1)有棋子的行一定是前面的几行。
(2)在每行内,有棋子的格子一定是前面的几格。
(3)一行内的棋子个数随行号单调不增。
所以用 map 存转移,合法的 S 是可以承受的。
| S | 为偶数时,转移:

f [ S ] = max { A i , j f [ add ( S , i ) ] }

否则 | S | 为奇数:
f [ S ] = max { B i , j f [ add ( S , i ) ] }

i 为枚举的行号。
j 表示第 i 行的最后一个棋子所在列号。
add ( S , i ) 表示在状态 S i 行第 j + 1 列放棋子达到的状态。

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;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/81232667