• 【洛谷P4576】棋盘游戏


    题目

    题目链接:https://www.luogu.com.cn/problem/P4576
    一个\(n*n(n\geq 2)\)棋盘上有黑白棋子各一枚。游戏者A和B轮流移动棋子,A先走。

    • A的移动规则:只能移动白棋子。可以往上下左右四个方向之一移动一格。
    • B的移动规则:只能移动黑棋子。可以往上下左右四个方向之一移动一格或者两格。

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

    思路:

    首先明显的一点就是,不存在平局,且A必胜当且仅当最开始白子与黑子就相邻。
    如果不是,那么就是B必胜。此时我们只需要让B尽快获胜,A尽量拖时间即可。
    \(f[i][j][k][l][dep]\)表示白子在\((i,j)\),黑子在\((k,l)\),已经走了\(dep\)步时,黑子获胜需要走的最少步数。
    那么白子从上下左右四个方向转移而来,取\(max\)值;黑子从上下左右上上下下左左右右(?)转移而来,取\(min\)值即可。
    记搜即可。
    那么边界是多少呢?
    这里给出一种比较偷鸡的方法(
    我们可以手动二分\(dep\)的最大值\(maxn\),如果\(dep>maxn\)就不再搜索下去。
    枚举白子和黑子的每一个起点,然后用\(ans\)记录在搜索深度不超过\(maxn\)的情况下的\(max(solve(i,j,k,l))\),其中\(solve(i,j,k,l)\)为当白点在\((i,j)\),黑点在\((k,l)\)时,黑子获胜的最少步数。
    如果\(ans=maxn+1\),那么就说明深度为\(maxn\)不够,否则已经足够。
    实测答案最大为\(58\),所以搜索到\(60\)层就够了。

    代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=25,MAXN=90,Inf=1e9;
    const int dx[]={0,0,0,-1,1,0,0,-2,2};
    const int dy[]={0,1,-1,0,0,-2,2,0,0};
    int n,sx,sy,tx,ty,f[N][N][N][N][MAXN];
    
    int dfs(int x,int y,int xx,int yy,int dep)
    {
    	if (xx==x && yy==y) return (dep&1) ? Inf : 0;
    	if (dep>60) return (dep&1) ? 0 : Inf;
    	if (f[x][y][xx][yy][dep]) return f[x][y][xx][yy][dep];
    	if (dep&1)
    	{
    		f[x][y][xx][yy][dep]=Inf;
    		for (register int i=1;i<=8;i++)
    			if (xx+dx[i]>=1 && xx+dx[i]<=n && yy+dy[i]>=1 && yy+dy[i]<=n)
    				f[x][y][xx][yy][dep]=min(f[x][y][xx][yy][dep],dfs(x,y,xx+dx[i],yy+dy[i],dep+1)+1);
    	}
    	else
    		for (register int i=1;i<=4;i++)
    			if (x+dx[i]>=1 && x+dx[i]<=n && y+dy[i]>=1 && y+dy[i]<=n)
    				f[x][y][xx][yy][dep]=max(f[x][y][xx][yy][dep],dfs(x+dx[i],y+dy[i],xx,yy,dep+1)+1);
    	return f[x][y][xx][yy][dep];
    }
    
    int main()
    {
    	scanf("%d%d%d%d%d",&n,&sx,&sy,&tx,&ty);
    	for (register int i=1;i<=4;i++)
    		if (sx+dx[i]==tx && sy+dy[i]==ty) return !printf("WHITE 1");
    	printf("BLACK %d",dfs(sx,sy,tx,ty,0));
    	return 0;
    }
    
  • 相关阅读:
    怎么导出SQL所有用户表的字段信息
    全面掌握C#中的拖放操作
    C#中使用Hook(钩子)
    如何在winform程序中显示网页
    设置socket.Receive()的等待时延
    局域网QQ(C#版)
    C#实现系统热键的功能
    使用C#在应用程序间发送消息
    某某人整理的c#.net函数列表
    C#串口通信编程类(修改版)
  • 原文地址:https://www.cnblogs.com/stoorz/p/12117027.html
Copyright © 2020-2023  润新知