kyeremal-poj2311-Cutting Game-sg函數

poj2311-Cutting Game

題意:給定一張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>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章