【洛谷】【博弈搜索】P4363 [九省聯考2018]一雙木棋chess

洛谷 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;
}
發佈了155 篇原創文章 · 獲贊 84 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章