题意:国际象棋,有四个人物。从(n,m)走到(1,1),走到(1,1)的人赢,先手赢输出B,后手赢输出G,平局输出D。
思路:可以先认为从(1,1)出发,到(n,m)点。本题就是各种博弈的汇总。
四种棋子的规则如下:(做题时确实不知道国际象棋的走法就百度了一下)
1、王(King):横、竖、斜都可以走,每次限走一格
2、车(Rook):横、竖均可走,不能斜走,格数不受限制,除王车易位的情况下,平时不能越子
3、马(Knight):每步棋先横走或竖走一格,再斜走一格(或者横两格竖一格,竖两格横一格),可以越子
4、后(Queen):横、竖、斜都可以走,格数不受限制,但不能越子
第一种很明显(1,1)是必败点,可以走到必败点的都是必胜点,而只能走到必胜点的都是必败点,所以很容易得出结论:n,m都为偶数则先手必败。
第二种把这个问题看做是两堆石子,取石子问题,是尼姆博弈,异或为0即相等的时候先手必败。
第三种先n,m如果if(m==n&&m%3==1)的倍数一定是先手输;如果是if((m%3==0&&n==m-1)||(n%3==0&&m==n-1)),则先手必胜,因为可以一步走到必败点,必胜;其余情况都是平局,因为如果一方存在赢的情况,另一方可以不走那步,把小的数-2,大的数-1,往墙上靠,谁也赢不了肯定是平局。
第四种也是看做两堆石子,取石子问题,是威佐夫博弈。用威佐夫博弈时注意是对m--,n--进行操作应为queue初始是在(1,1)点,相当于剩余的石子数是m--,n--。比赛时忘了这一点,debug了好长时间。
附AC代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <stack>
#include <cstring>
using namespace std;
int n,m;
void pying()///输出赢
{
puts("B");
}
void pshu()///输出输
{
puts("G");
}
void pping()///输出平
{
puts("D");
}
///找规律,n,m都为偶数则先手必败
///国王,每次只能向左或向下或左下移动一个格
void king()
{
if((n&1)&&(m&1))
pshu();
else
pying();
}
/*把这个问题看做是两堆石子,取石子问题,是尼姆博弈,异或为0即相等的时候先手必败。
其实直接找规律就好
车,每次能沿着水平方向或竖直方向走任意距离*/
void rook()
{
if(m==n)
pshu();
else
pying();
}
void knight()///骑士只能走”日“字
{
if(m==n&&m%3==1)
pshu();
else if((m%3==0&&n==m-1)||(n%3==0&&m==n-1))
pying();
else
pping();
}
///威佐夫博弈
///皇后可以沿 水平方向或 竖直方向或 正方形的对角线方向移动任意距离
void que()
{
m--;
n--;
if(n<m)
swap(n,m);
int k=n-m;
int n=(int)(k*(1+sqrt(5))/2.0);
if(n==m)
pshu();
else
pying();
}
int main(){
int T;scanf("%d",&T);
while(T--){
int flag;
cin >> flag >> m >> n;
if(flag==1) king();
else if(flag==2) rook();
else if(flag==3) knight();
else if(flag==4) que();
}
return 0;
}