題目鏈接:點擊打開鏈接
題目大意:給你四種棋子和一個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;
}