題意:給定一張n*m的矩形紙片,定義一個決策爲:從所有的紙片中任選一張(初始時僅有1張),沿平行於矩形邊剪切,將原矩形分割爲2個較小的矩形,雙方輪流決策,先剪出1*1紙片者獲勝,問先手是否必勝.
經典的組合遊戲問題,首先一張紙片經過一次裁剪變爲兩張,即一個遊戲變爲兩個子游戲,那麼子游戲和的sg值=子游戲A的sg值異或子游戲B的sg值,即sg[A∪B] = sg[A] xor sg[B].
很容易想出將(1,1)作爲終止條件.但是考慮組合遊戲本質爲在一張有向圖中從S到T雙方輪流移動,但此題中只要出現一張(1,1)遊戲便結束,以(1,1)作爲終止條件可能會產生有向圖並沒有走完但遊戲已經結束的情況.
稍加分析可知,某一方某一次決策之後產生了一張(1,k)的紙片,那麼這一方必敗(因爲另一方將(1,k)裁剪爲(1,1)&(1,k-1)可以直接獲勝),那麼對於(i,j)的紙片,最優決策一定會避免剪出(1,k)的紙片,當紙片無論怎麼剪都會出現(1,k),稱這張紙片爲"不可剪",當某紙片不可剪時,則會選擇其他紙片進行裁剪,易證,存在某一個狀態,所有的紙片都是"不可剪".
不可剪狀態的紙片有:(2,2), (2,3), (3,2), (3,3).
那麼只需要將這些紙片作爲終止條件問題就解決了.
code:
<span style="font-size:18px;">#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define REP(i, l, r) for (int i = l; i >= r; i--)
#define MAXN 1010
int n, m, sg[MAXN][MAXN];
bool xx[MAXN];
inline int mex() {int i; for (i = 0; xx[i]; ++i); return i;}
inline int getsg(int n, int m) {
if (~sg[n][m]) return sg[n][m];
memset(xx, 0, sizeof(xx));
rep(i, 2, n-2) xx[getsg(i, m) ^ getsg(n-i, m)] = 1;
rep(i, 2, m-2) xx[getsg(n, i) ^ getsg(n, m-i)] = 1;
return sg[n][m] = mex();
}
int main() {
memset(sg, -1, sizeof(sg));
sg[1][1] = sg[2][2] = sg[3][3] = sg[2][3] = sg[3][2] = 0;
while (scanf("%d%d", &n, &m) != EOF)
cout << (getsg(n, m) ? "WIN" : "LOSE") << endl;
return 0;
}
</span>