bzoj千题计划200: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));
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8227335.html