bzoj3106 [cqoi2013]棋盘游戏
Description
一个n*n(n>=2)棋盘上有黑白棋子各一枚。游戏者A和B轮流移动棋子,A先走。
l A的移动规则:只能移动白棋子。可以往上下左右四个方向之一移动一格。
l B的移动规则:只能移动黑棋子。可以往上下左右四个方向之一移动一格或者两格。
和通常的“吃子”规则一样,当某游戏者把自己的棋子移动到对方棋子所在的格子时,他就赢了。两个游戏者都很聪明,当可以获胜时会尽快获胜,只能输掉的时候会尽量拖延时间。你的任务是判断谁会赢,需要多少回合。
比如n=2,白棋子在(1,1),黑棋子在(2,2),那么虽然A有两种走法,第二个回合B总能取胜。
Input
输入仅一行,包含五个整数n, r1, c1, r2, c2,即棋盘大小和棋子位置。白色棋子在(r1,c1),黑色棋子在(r2,c2)(1<=r1,c1,r2,c2<=n)。黑白棋子的位置保证不相同。
Output
输出仅一行,即游戏结果。如果A获胜,输出WHITE x;如果B获胜,输出BLACK x;如果二者都没有必胜策略,输出DRAW。
Sample Input
2 1 1 2 2
Sample Output
BLACK 2
HINT
n<=20
正解:对抗搜索。
首先如果先手不能在第一步就赢,那么他就必输,因为后手可以把先手围在角落里。
然后设$f[0/1][y][a][b][c][d]$表示当前是先手/后手,总共走了几步,先手在$(a,b)$,后手在$(c,d)$,直接按照对抗搜索的方法转移就行。
以前没有写过对抗搜索,还是挂一个链接:博弈基础——极大极小搜索
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define inf (1<<30) 6 7 using namespace std; 8 9 const int d1[8]={1,0,-1,0,2,0,-2,0}; 10 const int d2[8]={0,1,0,-1,0,2,0,-2}; 11 12 int f[2][65][21][21][21][21],n,a,b,c,d; 13 14 il int gi(){ 15 RG int x=0,q=1; RG char ch=getchar(); 16 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 17 if (ch=='-') q=-1,ch=getchar(); 18 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 19 return q*x; 20 } 21 22 il int dfs(RG int x,RG int y,RG int a,RG int b,RG int c,RG int d){ 23 if (y>3*n) return inf; if (a==c && b==d) return x?inf:0; 24 if (f[x][y][a][b][c][d]) return f[x][y][a][b][c][d]; RG int res; 25 if (x){ 26 res=inf; 27 for (RG int i=0,X,Y;i<8;++i){ 28 X=c+d1[i],Y=d+d2[i]; 29 if (X>=1 && X<=n && Y>=1 && Y<=n) 30 res=min(res,dfs(x^1,y+1,a,b,X,Y)); 31 } 32 } else{ 33 res=0; 34 for (RG int i=0,X,Y;i<4;++i){ 35 X=a+d1[i],Y=b+d2[i]; 36 if (X>=1 && X<=n && Y>=1 && Y<=n) 37 res=max(res,dfs(x^1,y+1,X,Y,c,d)); 38 } 39 } 40 return f[x][y][a][b][c][d]=res+1; 41 } 42 43 int main(){ 44 #ifndef ONLINE_JUDGE 45 freopen("chess.in","r",stdin); 46 freopen("chess.out","w",stdout); 47 #endif 48 n=gi(),a=gi(),b=gi(),c=gi(),d=gi(); 49 if (abs(a-c)+abs(b-d)==1) puts("WHITE 1"); 50 else printf("BLACK %d\n",dfs(0,0,a,b,c,d)); 51 return 0; 52 }