POJ 2311-Cutting Game(Nim博弈-sg函式/記憶化搜尋)

kewlgrl發表於2016-05-12

Cutting Game

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3632   Accepted: 1352

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

Source

POJ Monthly,CHEN Shixi(xreborner)

題目意思:

有一張被分成w*h的格子的長方形紙張,兩人輪流沿著格子的邊界水平或垂直切割,將紙張分割成兩部分。切割了n次之後就得到了n+1張紙,每次都可以選擇切得的某一張紙再進行切割。最先切出只有一個格子的紙張(即有1*1格子的)的一方獲勝。當雙方都採取最優策略時,先手必勝還是必敗?

解題思路:

        初始只有一張紙,紙張的數量隨著切割而增加。
        當一張w*h的紙被分成兩張時,假設所得的兩張紙的sg值分別為sg1和sg2,
        則它們對應的狀態的sg值可以表示為sg1 XOR sg2
        在Nim中,不論有幾堆石子、初始狀態是怎樣的,只要XOR的結果相同,那麼對勝負是沒有影響的。這裡也一樣,只要SG值相同,即使發生分割,只要堆分割後的各部分取XOR,就可以利用這一個SG值來代表幾個遊戲複合而成的狀態,SG值也可以同樣地計算。
        瞭解了會發生分割的遊戲的處理方法之後,只要像以前的問題一樣,列舉所有一步能夠到達的狀態的SG值,就能夠計算SG值了。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <set>
#include <algorithm>
using namespace std;
const int MAXN=202;
int mem[MAXN][MAXN];//記憶化搜尋用的陣列
int grundy(int w,int h)
{
    if(mem[w][h]!=-1) return mem[w][h];//之前已經搜尋過了,可以直接返回記憶的值
    set<int>s;
    //保證邊長至少為2
    for(int i=2; w-i>=2; ++i)//剪w邊
        s.insert(grundy(i,h)^grundy(w-i,h));
    for(int i=2; h-i>=2; ++i)//剪h邊
        s.insert(grundy(w,i)^grundy(w,h-i));
    int res=0;
    while(s.count(res))
        ++res;
    return mem[w][h]=res;
}
int main()
{
    int w,h;
    memset(mem,-1,sizeof(mem));//初始化
    while(~scanf("%d%d",&w,&h))//輸入格子長寬
    {
        if(grundy(w,h)) puts("WIN");
        else puts("LOSE");
    }
    return 0;
}


相關文章