[CQOI2013]棋盘游戏

来源:互联网 发布:淘宝网新生活化妆品 编辑:程序博客网 时间:2024/06/02 05:10

题意

一个n*n(n>=2)棋盘上有黑白棋子各一枚。游戏者A和B轮流移动棋子,A先走。
A的移动规则:只能移动白棋子。可以往上下左右四个方向之一移动一格。
B的移动规则:只能移动黑棋子。可以往上下左右四个方向之一移动一格或者两格。
和通常的“吃子”规则一样,当某游戏者把自己的棋子移动到对方棋子所在的格子时,他就赢了。两个游戏者都很聪明,当可以获胜时会尽快获胜,只能输掉的时候会尽量拖延时间。你的任务是判断谁会赢,需要多少回合。

n20

分析

若一开始白棋在黑棋周围一格,则白棋可以获胜,否则白棋显然不可能获胜。
然后我们有一个非常重要的结论,黑棋获胜的步数Ans4n
证明详见http://blog.csdn.net/PhilipsWeng/article/details/47841649
这样我们可以限深记忆化搜索,步数dep>4n的状态我们可以不做。
f[dep][x1][y1][x2][y2]为过了dep个回合,白棋在(x1,y1),黑棋在(x2,y2)的状态。对于当前是白棋走(dep是偶数),它肯定不能获胜,则它肯定会选择黑棋最慢获胜的后继状态,状态记录的是最久还需几个回合黑棋才会获胜;反之,当前是黑棋走(dep是奇数),它会选择它最快获胜的后继状态,该状态为最快还需几个回合黑棋就会获胜。
那么转移方程就很容易推出了。

代码

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N = 22;const int flag[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};int f[4 * N][N][N][N][N],n,lim,x1,y1,x2,y2;int dfs(int dep,int x1,int y1,int x2,int y2) {    if (f[dep][x1][y1][x2][y2] != -1) return f[dep][x1][y1][x2][y2];    if (dep > lim) return -2;    if (x1 == x2 && y1 == y2) {        if (dep & 1) return -2;        return 0;    }    if (dep & 1) {        int re = (1 << 30);        for (int i = 0;i < 4;i ++) {            int x = x2 + flag[i][0],y = y2 + flag[i][1];            if (x < 1 || y < 1 || x > n || y > n) continue;            int cur = dfs(dep + 1,x1,y1,x,y);            if (cur == -2) continue;            re = min(re,cur + 1);        }        for (int i = 0;i < 4;i ++) {            int x = x2 + 2 * flag[i][0],y = y2 + flag[i][1] * 2;            if (x < 1 || y < 1 || x > n || y > n) continue;            int cur = dfs(dep + 1,x1,y1,x,y);            if (cur == -2) continue;            re = min(re,cur + 1);        }        if (re == (1 << 30)) re = -2;        return f[dep][x1][y1][x2][y2] = re;    }    else {        int re = 0;        for (int i = 0;i < 4;i ++) {            int x = x1 + flag[i][0],y = y1 + flag[i][1];            if (x < 1 || y < 1 || x > n || y > n) continue;            int cur = dfs(dep + 1,x,y,x2,y2);            if (cur == -2) return f[dep][x1][y1][x2][y2] = -2;            re = max(re,cur + 1);        }        return f[dep][x1][y1][x2][y2] = re;    }}int main() {    scanf("%d%d%d%d%d",&n,&x1,&y1,&x2,&y2);    if (abs(x1 - x2) + abs(y1 - y2) <= 1) printf("WHITE 1\n");     else{        lim = 4 * n;        memset(f,255,sizeof(f));        int ans = dfs(0,x1,y1,x2,y2);        if (ans >= 0) printf("BLACK %d\n",ans);        else printf("DRAW\n");    }}
0 0
原创粉丝点击