超级传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=2147
题目大意:
kiki和ZZ玩游戏,在n*m的矩阵里面,每次都是从[1,m]点出发,每次移动可以走到左,下,左下三个位置,轮到他不能移动的人算输,每一次都是kiki先移动,给出n和m的大小,问kiki是输还是赢。
P/N分析的用法:
P点 :前一个选手(Previous player)将取胜的位置称为必败点。
N点 :后一个选手(Next player)将取胜的位置称为必胜点。
他们的关系是:
任何N点都至少有一种方法可以进入P点
无论怎样操作,都只能去到N点的点是P点
也就是说,做这样的题目,先把边界点(或结束点)算出他是p点还是n点,然后推回去算出原点是什么点。
这题明显最后[n,0]点是p点,然后把下边和左边的点的属性先算出来,就可以算出整个棋盘的每个点的属性。
想法不错,但是题目数据时n,m<=2000,开始试图开了2000*2000的数组,超了空间- -||
后来在纸上画了一下
P N P N P N P
N N N N N N N
P N P N P N P
N N N N N N N
P N P N P N P
N N N N N N N
P N P N P N P
很明显:
当n和m为奇数的时候就是p点。
所以代码就很好写了:
PS:
以后要注意的一点是,这样的博弈题可以先不急着做,在纸上先画出一些,没准就能找到规律,变得好简单。
#include<iostream>
using namespace std;
int main()
{
int n,m;
while(scanf("%d %d",&n,&m) != EOF)
{
if(n == 0 && m == 0)
{
break;
}
if( (n & 1 == 1)&& (m & 1 == 1))
{
printf("What a pity!\n");
}
else
{
printf("Wonderful!\n");
}
}
return 0;
}