对于 皇上、车、马的判断 画图多试几个例子应该不难发现;
但是皇后,有毒……比赛的时候推唯一的感觉就是,皇后P点(必胜点)好多啊!最后只推出来(2,3)(4,6)两个N点……
比赛完看见有人用word画图,又学到了……
再次画了一遍,大概就是下面那样,果然图画的好规律就好找
(n,m)点是必败点,在这个点,轮到谁走谁输。
在(n,m)引三条射线,线上的点显然都是P点,因为它们都可以在下一步到达一个N点,使对手必败。
引出三条射线后又发现了两个N点,即图中的(n-1,m-2)和(n-2,m-1),再给这两个点画上射线……
逐步发现图中其它所有N点。
然后观察规律
1)N点肯定都是成对出现的,也就是说有(2,3)就有(3,2)所以只需要考虑一边。
2)每行每列最多只有一个N点。
3)仔细观察,如果把(n,m)当做(1,1),倒推,N点分别是(2,3),(4,6),(5,8),(7,11)…… 看(i,j)的差值是从1开始递增的,而且i是从2开始,(2,4,5,7……)看到没有3和6,发现如果N点(i,j)出现过,那么就不会出现(j,x)这种情况(之前说过只考虑一边,即先忽略(3,2)),所以只要在打表的时候弄个标记数组就可以了。
所以就可以这样打表了!
int mp[2005][2005],vis[2005];
void init()
{
mst(mp,0);
mp[1][1]=1;
for(int i=2,j=1;i<1005&&i+j<1005;i++,j++)
{
if(vis[i])
{
j--;
continue;
}
mp[i][i+j]=mp[i+j][i]=1;
vis[i]=vis[j+i]=1;
// printf("%d %d %d\n",i,i+j,mp[i][j+i]);
}
}
但是看到题解:
④皇后。
画画图后,我们可以将问题转化为:
“有两堆石子,每次可以在一堆里取任意(非空)颗(相当于是车的走法),或者在两堆里取相同(非空)颗(相当于是象的走法),取到最后一颗石子的人获胜,问先后手谁有必胜策略。”
百度发现这是多年前学过的威佐夫博弈:威佐夫博弈
我勒个去!
之前的观察规律推导差不多就是生生的把威佐夫博弈从无到有推了一遍。
【代码】
/* ***********************************************
Author :angon
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define REP(i,k,n) for(int i=k;i<n;i++)
#define REPP(i,k,n) for(int i=k;i<=n;i++)
#define scan(d) scanf("%d",&d)
#define scann(n,m) scanf("%d%d",&n,&m)
#define mst(a,k) memset(a,k,sizeof(a));
#define LL long long
#define maxn 1005
#define mod 100000007
int mp[2005][2005],vis[2005];
void init()
{
mst(mp,0);
mp[1][1]=1;
for(int i=2,j=1;i<1005&&i+j<1005;i++,j++)
{
if(vis[i])
{
j--;
continue;
}
mp[i][i+j]=mp[i+j][i]=1;
vis[i]=vis[j+i]=1;
// printf("%d %d %d\n",i,i+j,mp[i][j+i]);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
int t,type,n,m;
scan(t);
while(t--)
{
scanf("%d%d%d",&type,&n,&m);
if(type==1)
{
if( m%2==0 || n%2==0)
puts("B");
else
puts("G");
}
else if(type==3)
{
if((m+n)%3 != 2 || abs(m-n)>1)
puts("D");
else
{
if(m!=n)
puts("B");
else
puts("G");
}
}
else if(type==2)
{
if(m==n)
puts("G");
else
puts("B");
}
else
{
n--;m--;
if(n>m) swap(n,m);
m = (int) (m-n)*(sqrt(5)+1)/2; //威佐夫博弈
if(m==n)
//if(mp[n][m]) //打表也可
puts("G");
else
puts("B");
}
}
return 0;
}