1. 程式人生 > >【BZOJ3106】[CQOI2013] 棋盤遊戲(對抗搜尋)

【BZOJ3106】[CQOI2013] 棋盤遊戲(對抗搜尋)

點此看題面

大致題意: 在一張nnn*n的棋盤上有一枚黑棋子和一枚白棋子。白棋子先移動,然後是黑棋子。白棋子每次可以向上下左右四個方向中任一方向移動一步,黑棋子每次則可以向上下左右四個方向中任一方向移動一至二步。當某遊戲者把自己的棋子移動到對方棋子所在的格子時,他就贏了。兩個遊戲者都很聰明,可以獲勝時會盡快獲勝,必輸時會盡量拖延時間。試判斷誰會贏,需要多少回合。

對抗搜尋

這道題的做法應該是對抗搜尋

一波簡單的分析

我們先來對題目進行一波簡單的分析。

不難發現,因為黑棋每次能走的步數大於白棋每次能走的步數,所以除非白棋第一步就吃掉黑棋,否則白棋必輸

既然這樣,我們只需特判白棋獲勝的情況,然後題目就轉換成了求黑棋追上白棋所需的時間

這樣一來,就變成了一道較簡單的對抗搜尋題了。

直接用記憶化優化即可(當然,理論上來講AlphaBetaAlpha-Beta剪枝也可以做,但我沒去試過)。

程式碼

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define Fsize 100000 #define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++) #define pc(ch) (putchar(ch)) #define N 20 int OutputTop=0;char Fin[Fsize],*FinNow=Fin,*FinEnd=Fin,OutputStack[Fsize]; using namespace std; int n,X1,Y1,X2,Y2,res[N+1][N+1]
[N+1][N+1][2][3*N+1]; inline void read(int &x) { x=0;static char ch; while(!isdigit(ch=tc())); while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc())); } inline void write(int x) { if(!x) return (void)pc('0'); while(x) OutputStack[++OutputTop]=x%10+48,x/=10; while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop; } inline int dfs(int X1,int Y1,int X2,int Y2,int Which,int Step)//對抗搜尋 { if(Step>3*n) return 1e9;//深度限制,以防無限制地搜尋下去(可以保證最終的答案≤3n) if(res[X1][Y1][X2][Y2][Which][Step]) return res[X1][Y1][X2][Y2][Which][Step];//如果已經訪問當前狀態,就返回上次求解出的答案 if(X1==X2&&Y1==Y2) return Which?1e9:0;//如果已經重合了,就退出函式 register int i,t,ans=Which?1e9:0; Which^=1,++Step;//更新Which和Step為下一個狀態,以避免不斷地運算 if(Which)//如果下一個輪黑棋操作,即當前為白棋操作 { if(X1>1) t=dfs(X1-1,Y1,X2,Y2,Which,Step),ans=max(ans,t); if(X1<n) t=dfs(X1+1,Y1,X2,Y2,Which,Step),ans=max(ans,t); if(Y1>1) t=dfs(X1,Y1-1,X2,Y2,Which,Step),ans=max(ans,t); if(Y1<n) t=dfs(X1,Y1+1,X2,Y2,Which,Step),ans=max(ans,t); } else//如果當前為黑棋操作 { if(X2>1) t=dfs(X1,Y1,X2-1,Y2,Which,Step),ans=min(ans,t); if(X2>2) t=dfs(X1,Y1,X2-2,Y2,Which,Step),ans=min(ans,t); if(X2<=n-1) t=dfs(X1,Y1,X2+1,Y2,Which,Step),ans=min(ans,t); if(X2<=n-2) t=dfs(X1,Y1,X2+2,Y2,Which,Step),ans=min(ans,t); if(Y2>1) t=dfs(X1,Y1,X2,Y2-1,Which,Step),ans=min(ans,t); if(Y2>2) t=dfs(X1,Y1,X2,Y2-2,Which,Step),ans=min(ans,t); if(Y2<=n-1) t=dfs(X1,Y1,X2,Y2+1,Which,Step),ans=min(ans,t); if(Y2<=n-2) t=dfs(X1,Y1,X2,Y2+2,Which,Step),ans=min(ans,t); } return res[X1][Y1][X2][Y2][Which^1][Step-1]=ans+1; } int main() { read(n),read(X1),read(Y1),read(X2),read(Y2); if(abs(X1-X2)+abs(Y1-Y2)<=1) return puts("WHITE 1"),0;//特判白棋獲勝的情況 return pc('B'),pc('L'),pc('A'),pc('C'),pc('K'),pc(' '),write(dfs(X1,Y1,X2,Y2,0,1)),0; }