题目链接:点击打开链接
题目大意:给你四种棋子和一个n*m的棋盘,从(1,1)走到(n,m)问输赢平
解题思路:分析每一种棋子:
对于国王来说,相当于是在两堆石子中取,每次只能从一堆中取一个或者两堆一起各取一个:
(0,0)为必败态
(1,1)就是必胜态
那么到(1,1)奇数步距离的就一定也是必败态,说以(1,x)(x为奇数一定是必败态)
(2,2)是必胜态因为他可以转化成(1,1)
于是我们分析(3,3),下一步只能是(3,2)或者(2,3)这些都是一步到(2,2)的于是(3,3)为必败态,
同上(3,x)(x为奇数一定是必败态)
推广所有(x,y)只要x和y都是奇数就是必败态。
对于城堡来说,相当于是在两堆石子中取,每次从一堆中取任意个(典型的NIM博弈),直接n|m判胜负。
对于骑士来说,这里有点麻烦,因为会出现平局的情况。
我们来考虑下必胜的情况(3,3)对于这个点对方不论怎么走你都能获胜,于是推广(6,6),(9,9)。。。。。。都可以,这些点为必胜点,
而这些点一步到的点为必败点,
剩下的为平局。
最后,对于王后来说,相当于是在两堆石子中取,每次只能从一堆中取任意个或者两堆一起取相同任意个:
典型的威佐夫博弈,判断小的值是否等于1.618*差值就好。
代码:
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include "cstdio"
#include "string"
#include "string.h"
#include "map"
#include "bitset"
using namespace std;
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;
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()
{
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;
}
//ret=knight[sn][sm];
}
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;
}