kyeremal-poj2311-Cutting Game-sg函数

13 篇文章 0 订阅
1 篇文章 0 订阅

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值