kiki's game
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 40000/10000 K (Java/Others)
Total Submission(s): 9663 Accepted Submission(s): 5817
Problem Description
Recently kiki has nothing to do. While she is bored, an idea appears
in his mind, she just playes the checkerboard game.The size of the
chesserboard is n*m.First of all, a coin is placed in the top right
corner(1,m). Each time one people can move the coin into the left, the
underneath or the left-underneath blank space.The person who can't make a
move will lose the game. kiki plays it with ZZ.The game always starts
with kiki. If both play perfectly, who will win the game?
Input
Input
contains multiple test cases. Each line contains two integer n, m
(0<n,m<=2000). The input is terminated when n=0 and m=0.
Output
If kiki wins the game printf "Wonderful!", else "What a pity!".
Sample Input
5 3
5 4
6 6
0 0
Sample Output
What a pity! Wonderful! Wonderful!
题意:两个人从一个 n*m 的矩阵的右上角开始走,可以往左,往下,往左下走,如果下一个人无路可走了,那么当前的人就获胜,问最终获胜的人是谁?是第一个人,输出Wonderful!,否则输出What a pity!
题解:
必败点(P点) :前一个选手(Previous player)将取胜的位置称为必败点(第一个人获胜)。
必胜点(N点) :下一个选手(Next player)将取胜的位置称为必胜点(第二个人获胜)。
必败/必胜点的属性:
(1) 所有终结点是必败点(P点);
(2) 从任何必胜点(N点)操作,至少有一种方法可以进入必败点(P点);
(3)无论如何操作, 从必败点(P点)都只能进入必胜点(N点).
取子游戏算法实现:
步骤1:将所有终结位置标记为必败点(P点);
步骤2: 将所有一步操作能进入必败点(P点)的位置标记为必胜点(N点)
步骤3:如果从某个点开始的所有一步操作都只能进入必胜点(N点) ,则将该点标记为必败点(P点) ;
步骤4: 如果在步骤3未能找到新的必败(P点),则算法终止;否则,返回到步骤2。
拿5*6的矩阵举个例子:
首先:根据第一步,我们可以确定 (n,1) 是终结位置,标记为 P
然后画出NP图:
PNPNPN
NNNNNN
PNPNPN
NNNNNN
PNPNPN
可以发现这个图是kiki赢,然后找一下里面子图的规律,比如说红色的子图,发现只有当 n 和 m都为奇数时,第一个点才会是必败点,其余情况都是必胜点。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; int n,m; int main() { while(scanf("%d%d",&n,&m)!=EOF,n+m){ if(n%2==1&&m%2==1){ printf("What a pity! "); continue; }else printf("Wonderful! "); } return 0; }