bzoj3106: [cqoi2013]棋盘游戏(对抗搜索)
http://www.lydsy.com/JudgeOnline/problem.php?id=3106
白棋如果第一步不能赢,那么一定输
因为可以黑棋走的距离比白棋大,黑棋可以下一步吃掉白棋,也可以下一步离开白棋的吃子范围
n才20,我们可以dfs搜索所有的局面求黑棋取胜的回合数
记录当前状态到游戏结束的回合数
如果现在白棋走,那它要尽可能的拖延时间,所以就是所有的后继状态取大
如果现在黑棋走,那它要尽快的取胜,所以就是所有的后继状态取小
边界是当两个棋子到同一位置时,根据前面的分析,应该必须是黑棋完成的最后一步
而dfs到下一回合,双方互换
所以当前如果是白棋,就return 0
如果是黑旗,就return 无穷大
#include<cstdio> #include<algorithm> using namespace std; int n; int dp[2][61][21][21][21][21]; int dfs(int who,int now,int r1,int c1,int r2,int c2) { if(now>n*3) return n*3; if(r1==r2 && c1==c2) return who ? n*3 : 0; if(dp[who][now][r1][c1][r2][c2]) return dp[who][now][r1][c1][r2][c2]; int ans; if(!who) { ans=0; if(r1>1) ans=max(ans,dfs(1,now+1,r1-1,c1,r2,c2)); if(r1<n) ans=max(ans,dfs(1,now+1,r1+1,c1,r2,c2)); if(c1>1) ans=max(ans,dfs(1,now+1,r1,c1-1,r2,c2)); if(c1<n) ans=max(ans,dfs(1,now+1,r1,c1+1,r2,c2)); } else { ans=n*3; if(r2>1) ans=min(ans,dfs(0,now+1,r1,c1,r2-1,c2)); if(r2>2) ans=min(ans,dfs(0,now+1,r1,c1,r2-2,c2)); if(r2<n) ans=min(ans,dfs(0,now+1,r1,c1,r2+1,c2)); if(r2<n-1) ans=min(ans,dfs(0,now+1,r1,c1,r2+2,c2)); if(c2>1) ans=min(ans,dfs(0,now+1,r1,c1,r2,c2-1)); if(c2>2) ans=min(ans,dfs(0,now+1,r1,c1,r2,c2-2)); if(c2<n) ans=min(ans,dfs(0,now+1,r1,c1,r2,c2+1)); if(c2<n-1) ans=min(ans,dfs(0,now+1,r1,c1,r2,c2+2)); } ans++; return dp[who][now][r1][c1][r2][c2]=ans; } int main() { int r1,c1,r2,c2; scanf("%d%d%d%d%d",&n,&r1,&c1,&r2,&c2); if(abs(r1-r2)+abs(c1-c2)<=1) { printf("WHITE 1"); return 0; } printf("BLACK %d",dfs(0,0,r1,c1,r2,c2)); }