【BZOJ5248】【九省聯考2018】一雙木棋(搜索,哈希)
阿新 • • 發佈:2018-04-07
count const 一個 body 如果 直接 一個人 沒有 span
采用最優策略且知道對方會采用最優策略,那麽,最終的結果如何
也就是對於第一個人,
它一定從當前局面可以到達的所有局面中,選擇一個最大的走。
第二個人一定會從當前局面所有可以到達的局面中,選擇一個最小的走。
(這就是所謂的\(min-max\)搜索???或者叫對抗搜索??)
【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】一雙木棋(搜索,哈希)