题意
在一个 n×m 的棋盘左上角有一个棋子(四种类型之一),要求移动到右下角(只能往右或者往下),问都采取最优策略的情况下,先手方是否必胜(或者平局)。
思路
从来没做过这么奇怪的博弈题,写完就会下国际象棋了。。
我们按棋子的类型分类讨论
king(国王)
走法:右 1 或下1 或右下 1
当且仅当n 和 m 都为奇数时,先手必败,否则必胜。
可以枚举3×3 的情况,先手必败,对于其他的必败情况,一定可以最终转换到 3×3 的必败情形(这个我没仔细推,可能有点想当然)rook(车)
走法:右 n 或下n
这个一看就是nim博弈有没有,石子有 2 堆嘛。。
当然因为只有2 堆,分类讨论也是可以的,当且仅当 n=m 时必败。knight(骑士/马)
可以发现能够平局的只有这种情况。
走法:右 1 下2 或 右 2 下1
首先,对于 4×4 的情况先手方是必败的,实际上,能够必败的也就只有这类情况,即( n=m 且 (n−1)≡0(mod3) )。即无论先手方怎么走(只有两种走法),后手都可以走回先手必败的局面。
必胜的情况,就是在必败的情况之上,加上先手能走的一步,即( n÷3=m÷3 且 n%3 与 m%3 中一个为1,一个为2)
否则平局。queen(皇后)
走法:右n或下n或右下n
这个是威佐夫博弈的模型,从2堆石子中任选1堆取或者2堆取一样的数目(不能不取)。
开始的几个必败态为(数字表示能走的步数,即 (n−1,m−1) ):
(0,0) (1,2) (3,5) (4,7) 。。
即第一个数是从来没出现过的最小自然数,第二个数和第一个数的关系为:
Y=X×(5√+1)2
黄金分割比+1倍有木有。。
代码
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=1e3+50;
const int Mod=1e9+7;
const double PI=acos(-1);
const double d1618=(sqrt(5)+1)/2;
typedef long long ll;
using namespace std;
const int KNIGHT=3;
const int QUEEN=4;
const int KING=1;
const int ROOK=2;
const int WIN=1;
const int DRAW=0;
const int LOSE=-1;
int t,n,m;
int sn,sm;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
// initKnight();
int T; scanf("%d",&T);
while(T--){
scanf("%d %d %d",&t,&n,&m);
sn=n-1;
sm=m-1;
int ret,tmp;
if (t==KNIGHT){
if (sn==sm && sn%3==0 && sm%3==0) ret=LOSE;
else {
int tn=sn%3,tm=sm%3;
if (tn>tm) swap(tn,tm);
if (sn/3==sm/3 && tn==1 && tm==2) ret=WIN;
else ret=DRAW;
}
}else if (t==KING){
if ((n&1) && (m&1)) tmp=0;
else tmp=1;
if (tmp==0) ret=LOSE;
else ret=WIN;
}else if (t==ROOK){
tmp=sn^sm;
if (tmp==0) ret=LOSE;
else ret=WIN;
}else if (t==QUEEN){
if (sn>sm) swap(sn,sm);
int nn=(sm-sn)*d1618;
if (nn==sn) ret=LOSE;
else ret=WIN;
}
if (ret==WIN) puts("B");
else if (ret==LOSE) puts("G");
else puts("D");
}
return 0;
}