版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意
初始只有一张 的纸片,每次可以选一张已有的纸片横切一刀(变成 的一片加上 的一片)或者竖切一刀(变成 的一片和 的一片)得到两张纸片。
最先得到 的纸片的人获胜。
多组询问,给定初始纸片大小,求先手是否有必胜策略。
思路
简单博弈论。 但是考场上没有想出来。
发现这题与一般SG函数能处理的问题不同的点在于:他只要有一张 就算获胜,也就是只要一个子游戏无法进行就算结束;而不是所有纸片都变成 才结束,即要求把所有游戏都无法进行才算结束。
但是假如我们把 、 、 的纸片看成初始的必败态,情况就不一样了。首先我们排除 的纸片,因为切出这种纸片必然导致自己的失败。然后发现对于一个上述三种初始必败的纸片,只要有人先对他下手了,那后手必胜,而游戏结束的条件就不是 “先得到一张 或 或 的人赢”,而是 “将所有纸片都变成上述三种纸片的人赢” 。这就是一个正常的SG函数了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 200 + 10;
int n = 200, sg[N][N], x, y;
bool tmp[N*2];
void init(int x, int y)
{
memset(tmp, 0, sizeof(tmp));
for (int i = 2; i <= x-2; ++ i)
tmp[sg[i][y]^sg[x-i][y]] = 1;
for (int i = 2; i <= y-2; ++ i)
tmp[sg[x][i]^sg[x][y-i]] = 1;
for (int i = 0; i < (N<<1); ++ i)
if (!tmp[i]){
sg[x][y] = i;
break;
}
}
int main()
{
for (int i = 2; i <= n; ++ i)
for (int j = 2; j <= n; ++ j)
init(i, j);
while(scanf("%d%d", &x, &y) == 2)
puts(sg[x][y] ? "WIN" : "LOSE");
return 0;
}