zoukankan      html  css  js  c++  java
  • BZOJ 3106 棋盘游戏

    Description

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

    Input

    输入仅一行,包含五个整数(n, r_{1}, c_{1}, r_{2}, c_{2}),即棋盘大小和棋子位置。白色棋子在((r_{1},c_{1})),黑色棋子在((r_{2},c_{2})(1 le r_{1},c_{1},r_{2},c_{2} le n))。黑白棋子的位置保证不相同。

    Output

    输出仅一行,即游戏结果。如果A获胜,输出WHITE (x);如果B获胜,输出BLACK (x);如果二者都没有必胜策略,输出DRAW。

    Sample Input

    2 1 1 2 2

    Sample Output

    BLACK 2

    HINT

    (n le 20)

    首先有个结论可以判胜负:
    如果A与B只相差一格,那么A一定获胜;否则B一定获胜。那个平局只是来卖个萌的。(B走的快一些)
    然后就是求合法的步数了,这个是CLB告诉我的极大极小搜索。
    我开始裸搜果断TLE,加了记忆化,果断WA,没怎么打过,怎么调也调不对,最后还是参照了别人的程序长了见识。

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    #define inf (1<<30)
    #define lim (3*n+2)
    #define maxn (25)
    const int xx[] = {0,1,0,-1},yy[] = {1,0,-1,0};
    int n,X1,X2,Y1,Y2,ans; int vis[maxn][maxn][maxn][maxn][maxn*3][2];
    
    inline bool okay(int x,int y) { return x > 0&&x<=n&&y > 0&&y<=n; }
    
    inline int dfs(bool now,int a1,int b1,int a2,int b2,int step)
    {
    	if (step > lim) return inf;
    	if (vis[a1][b1][a2][b2][step][now]) return vis[a1][b1][a2][b2][step][now];
    	else if (a1 == a2&&b1 == b2)
    	{
    		if (now) return inf;
    		return 0;
    	}
    	int ret;
    	if (!now)
    	{
    		ret = 0;
    		for (int i = 0;i < 4;++i)
    			if (okay(a1+xx[i],b1+yy[i]))
    				ret = max(dfs(now^1,a1+xx[i],b1+yy[i],a2,b2,step+1),ret);
    	}
    	else
    	{
    		ret = inf;
    		for (int j = 1;j <= 2;++j)
    			for (int i = 0;i < 4;++i)
    				if (okay(a2+j*xx[i],b2+j*yy[i]))
    					ret = min(dfs(now^1,a1,b1,a2+j*xx[i],b2+j*yy[i],step+1),ret);
    	}
    	return vis[a1][b1][a2][b2][step][now] = ++ret;
    }
    
    int main()
    {
    	freopen("3106.in","r",stdin);
    	freopen("3106.out","w",stdout);
    	scanf("%d %d %d %d %d
    ",&n,&X1,&Y1,&X2,&Y2);
    	if (abs(X1-X2)+abs(Y1-Y2) == 1) printf("WHITE 1");
    	else
    	{
    		printf("BLACK ");
    		printf("%d",dfs(0,X1,Y1,X2,Y2,0));		
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    多项式插值取模哈希标记法
    AC自助机
    [OIBH] 糖果盒(Candy Box)——又一个最大子矩形
    windows phone 之ListBox数据绑定
    WP学习笔记
    为TextArea添加maxlength属性
    让整个网页(LOGO图片)色调全部变灰的方法(CSS写法)
    JS调试加断点
    Container.ItemIndex 获取到行的序号
    c# Invoke 与 BeginInvoke
  • 原文地址:https://www.cnblogs.com/mmlz/p/4306236.html
Copyright © 2011-2022 走看看