「poj 2311」Cutting Game (博弈论,SG函数)

poj 2311
题意:有一张$n \times m$的格子,两个玩家轮流每次可以剪下一行/一列,第一个剪下$1\times 1$的玩家获胜。两个玩家都采用最优决策,求先手是否必胜。

考虑将一张格子定义为一个有向图游戏,最终游戏的$\text{SG}$值即为所有有向图游戏的异或和
考虑这个$1\times 1$获胜不符合我们有向图游戏的定义,我们做一些转化。
考虑到我们剪下$1 \times x, x \times 1$会使得当前的玩家必败。那么我们可以将局面
$(2,3), (3,2), (2,2)$设为必败局面,然后
$$
\text{SG}(x,y)=\text{mex}(\text{SG}(x - i,y) ⊕ \text{SG}(i,y) \cup \text{SG}(x ,y- i) ⊕ \text{SG}(x,i))
$$

注意多组询问完全可以将之前的$\text{SG}$函数值保留。

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<queue>
#include<string>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    int w, h, sg[205][205];

    int dfs(int x, int y) {
        if (sg[x][y] >= 0) return sg[x][y];
        int mex[205];
        ms(mex, 0);
        for (int i = 2; i <= x - 2; ++i)
            mex[dfs(i, y) ^ dfs(x - i, y)] = 1;
        for (int i = 2; i <= y - 2; ++i)
            mex[dfs(x, i) ^ dfs(x, y - i)] = 1;    
        for (int i = 0; ; ++i) 
        if (!mex[i]) return sg[x][y] = i;
    }

    void clean() {
    }
    int solve() {

        clean();

        if (dfs(w, h) == 0) puts("LOSE");
        else puts("WIN");

        return 0;
    }  
}
using flyinthesky::sg;
using flyinthesky::w;
using flyinthesky::h;
int main() {
    ms(sg, -1);
    sg[2][2] = 0, sg[2][3] = 0, sg[3][2] = 0;
    while (scanf("%d%d", &w, &h) == 2) flyinthesky::solve();
    return 0;
}
/*
*/
------ 本文结束 ------