1. 程式人生 > >【BZOJ5248】【九省聯考2018】一雙木棋(搜索,哈希)

【BZOJ5248】【九省聯考2018】一雙木棋(搜索,哈希)

count const 一個 body 如果 直接 一個人 沒有 span

【BZOJ5248】【九省聯考2018】一雙木棋(搜索,哈希)

題面

BZOJ

Description

菲菲和牛牛在一塊n行m列的棋盤上下棋,菲菲執黑棋先手,牛牛執白棋後手。棋局開始時,棋盤上沒有任何棋子,
兩人輪流在格子上落子,直到填滿棋盤時結束。落子的規則是:一個格子可以落子當且僅當這個格子內沒有棋子且
這個格子的左側及上方的所有格子內都有棋子。
棋盤的每個格子上,都寫有兩個非負整數,從上到下第i行中從左到右第j列的格子上的兩個整數記作Aij、Bij。在
遊戲結束後,菲菲和牛牛會分別計算自己的得分:菲菲的得分是所有有黑棋的格子上的Aij之和,牛牛的得分是所
有有白棋的格子上的Bij的和。
菲菲和牛牛都希望,自己的得分減去對方的得分得到的結果最大。現在他們想知道,在給定的棋盤上,如果雙方都

采用最優策略且知道對方會采用最優策略,那麽,最終的結果如何

Input

第一行包含兩個正整數n,m,保證n,m≤10。
接下來n行,每行m個非負整數,按從上到下從左到右的順序描述每個格子上的
第一個非負整數:其中第i行中第j個數表示Aij。
接下來n行,每行m個非負整數,按從上到下從左到右的順序描述每個格子上的
第二個非負整數:其中第i行中第j個數表示Bij
n, m ≤ 10 , Aij, Bij ≤ 100000

Output

輸出一個整數,表示菲菲的得分減去牛牛的得分的結果。

Sample Input

2 3

2 7 3

9 1 2

3 7 2

2 3 1

Sample Output

2

題解

考慮一下所謂的兩個人都是走最優策略

也就是對於第一個人,
它一定從當前局面可以到達的所有局面中,選擇一個最大的走。
第二個人一定會從當前局面所有可以到達的局面中,選擇一個最小的走。
(這就是所謂的\(min-max\)搜索???或者叫對抗搜索??)

考慮一下所有的狀態,一定是一個從上往下的階梯型
因為\(n,m<=10\)
所以我們可以用一個\(n\)位的\(m+1\)進制數把當前下完的輪廓給哈希一下。

那麽,對於一個局面,我們可以做記憶化搜索,
我們只需要根據局面當前下子的是誰,決定這個狀態是最大還是最小。這樣用\(map\)壓下當前所有狀態,直接搜索即可。。

要是讓我考我肯定做不出來

#include<iostream>
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 15 inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } const int Base=11; map<ll,int> M; int ln[MAX],n,m; int A[MAX][MAX],B[MAX][MAX]; ll Hash(){ll ret=0;for(int i=1;i<=n;++i)ret=ret*Base+ln[i];return ret;} void UnHash(ll st){for(int i=n;i;--i)ln[i]=st%Base,st/=Base;} int Next(){int ret=0;for(int i=1;i<=n;++i)ret+=ln[i];return ret&1;} int dfs(ll st) { if(M.count(st))return M[st]; UnHash(st); int opt=Next(),ret=opt?1e9:-1e9; for(int i=1;i<=n;++i) if(ln[i-1]>ln[i]) { ln[i]++; ll now=Hash(); opt?ret=min(ret,dfs(now)-B[i][ln[i]]):ret=max(ret,dfs(now)+A[i][ln[i]]); ln[i]--; } return M[st]=ret; } int main() { n=read();ln[0]=m=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) A[i][j]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) B[i][j]=read(); ll all=0; for(int i=1;i<=n;++i)all=all*Base+m; M[all]=0; dfs(0); printf("%d\n",M[0]); return 0; }

【BZOJ5248】【九省聯考2018】一雙木棋(搜索,哈希)