洛谷 P4363 [九省聯考2018]一雙木棋chess
題目大意
分析
根據題目所給定的規則,可以發現對於每一行,其下面一行上放的棋子數目不可能多於上面的一行。
所以我們可以將每行上已經用了的棋子個數記錄下來,這樣就能夠很輕鬆的表示出一個棋盤了。
如果直接暴力加上 alpha - beta 剪枝的話顯然會直接 T 飛。
同時我們發現隨着步數的增加,棋子也會越來越多,換句話說這東西就是一個 DAG 。再打一打暴力可以發現這個搜索的方案有很多是重複的。
我們就可以考慮記憶化一下。
然而我們發現如果我們直接採用set
或者map
暴力記錄方案,不開 O2 根本過不了。。。(看看我的慘痛教訓吧)
原諒我打錯了,應該是 gp_hash_table…
那麼我們就考慮將我們記錄的狀態哈希一下。
一種 比較好的 方法是像我一樣把我們記錄下的每行上的棋子個數壓成一個 13 進制數,然後塞進哈希表裏面。
參考代碼
註釋掉的部分是用的pd_bs
庫的哈希表。 這東西怎麼比我寫的哈希錶慢啊QAQ…
#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int Maxn = 10;
const ll P = 13;
const int HashMod = 563869;
int N, M;
int A[Maxn + 5][Maxn + 5], B[Maxn + 5][Maxn + 5];
int cnt[Maxn + 5];
inline ll calc_hash() {
ll ret = 0;
for(register int i = 1; i <= N; i++)
ret = ret * P + cnt[i];
return ret;
}
inline void hash_inverse(ll hashval) {
for(register int i = N; i >= 1; i--)
cnt[i] = hashval % P, hashval /= P;
}
//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
//using namespace __gnu_pbds;
//gp_hash_table<ll, int> f;
struct HashTable {
struct HashNode {
ll val;
int x;
HashNode *nxt;
};
HashNode pool[HashMod * 20 + 5];
HashNode *hcnt, *head[HashMod + 5];
HashTable() {
hcnt = &pool[0];
}
void addnode(int h, ll val, int x) {
HashNode *p = ++hcnt;
p->val = val, p->x = x;
p->nxt = head[h], head[h] = p;
}
void hash(ll val, int x) {
int t = val % HashMod;
addnode(t, val, x);
}
int query(ll val) {
int t = val % HashMod;
for(HashNode *p = head[t]; p != NULL; p = p->nxt)
if(p->val == val) return p->x;
return -1;
}
};
HashTable f;
int DFS(ll now, int typ) {
// if(f[now]) return f[now];
int t = f.query(now);
if(t != -1) return t;
hash_inverse(now);
int ret = typ ? -INF : INF;
for(register int i = 1; i <= N; i++)
if(cnt[i] < cnt[i - 1]) {
cnt[i]++;
ll nxt = calc_hash();
if(typ) ret = max(ret, DFS(nxt, 0) + A[i][cnt[i]]);
else ret = min(ret, DFS(nxt, 1) - B[i][cnt[i]]);
cnt[i]--;
}
// return f[now] = ret;
f.hash(now, ret);
return ret;
}
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d %d", &N, &M);
for(register int i = 1; i <= N; i++)
for(register int j = 1; j <= M; j++)
scanf("%d", &A[i][j]);
for(register int i = 1; i <= N; i++)
for(register int j = 1; j <= M; j++)
scanf("%d", &B[i][j]);
for(register int i = 1; i <= N; i++)
cnt[i] = M;
// f[calc_hash()] = 1;
f.hash(calc_hash(), 0);
cnt[0] = M;
// printf("%d\n", DFS(0ULL, 1) - 1);
printf("%d\n", DFS(0ULL, 1));
return 0;
}