- 原题如下:
Cutting Game
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5721 Accepted: 2083 Description
Urej loves to play various types of dull games. He usually asks other people to play with him. He says that playing those games can show his extraordinary wit. Recently Urej takes a great interest in a new game, and Erif Nezorf becomes the victim. To get away from suffering playing such a dull game, Erif Nezorf requests your help. The game uses a rectangular paper that consists of W*H grids. Two players cut the paper into two pieces of rectangular sections in turn. In each turn the player can cut either horizontally or vertically, keeping every grids unbroken. After N turns the paper will be broken into N+1 pieces, and in the later turn the players can choose any piece to cut. If one player cuts out a piece of paper with a single grid, he wins the game. If these two people are both quite clear, you should write a problem to tell whether the one who cut first can win or not.Input
The input contains multiple test cases. Each test case contains only two integers W and H (2 <= W, H <= 200) in one line, which are the width and height of the original paper.Output
For each test case, only one line should be printed. If the one who cut first can win the game, print "WIN", otherwise, print "LOSE".Sample Input
2 2 3 2 4 2
Sample Output
LOSE LOSE WIN
- 题解:这种会发生分割的游戏,也可以计算Grundy值
当w*h的纸张分成两张时,假设所分得的纸张的Grundy值分别为g1和g2,则这两张纸对应的状态的Grundy值可以表示为g1 xor g2。
在Nim中,不论有几堆石子,初始状态是怎样的,只要xor的结果相同,那么对胜负是没有影响的。这里也是同样的,只要Grundy值相同,即便发生分割,只要对分割后的各部分取xor,就可以用这一个Grundy值来代表几个游戏复合而成的状态,Grundy值也可以同样计算(也可以说,这是因为xor运算的结合律)。
另,切割纸张时,一旦切割出了长或宽为1的纸张,下一步就一定能够切割出1*1的纸张,所以可以知道此时必败。因此,切割纸张时,总要保证长和宽至少为2(无论如何都不能保证时,就是必败态。此时根据Grundy值的定义,不需要特别处理其Grundy值也是0)。 - 代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<set> 4 5 using namespace std; 6 7 const int MAX_WH=200; 8 int w, h; 9 int men[MAX_WH+1][MAX_WH+1]; 10 11 int grundy(int w, int h) 12 { 13 if (men[w][h]!=-1) return men[w][h]; 14 set<int> S; 15 for (int i=2; w-i>=2; i++) S.insert(grundy(i, h) ^ grundy(w-i, h)); 16 for (int i=2; h-i>=2; i++) S.insert(grundy(w, i) ^ grundy(w, h-i)); 17 int res=0; 18 while (S.count(res)) res++; 19 return men[w][h]=res; 20 } 21 22 int main() 23 { 24 memset(men, -1, sizeof(men)); 25 while (~scanf("%d %d", &w, &h)) 26 { 27 if (grundy(w, h)!=0) puts("WIN"); 28 else puts("LOSE"); 29 } 30 }