2013金山西山居创意游戏程序挑战赛——复赛(1) 涂色游戏

sg函数的应用

http://acm.hdu.edu.cn/showproblem.php?pid=4559

sg函数中最重要的是要弄清楚。。。状态分割、状态转移之间的关系

分割代表从头结点进入某一后继进行状态转移,下次还可以重复这个操作。对原点进行分割,sg = sg(1)^sg(2)....

转移代表从一点开始向其后继移动,但下次就只能从该后继开始。 sg(i) = min(k 不属于 {x | x = sg(j), j是i的后继 } ) sg(i) >= 0


通常来说分割后的子树是互不影响的,所以在确定使用状态分割还是转移的时候这个很关键


本题中,将矩形按竖列分割为:连续的空矩形,非空矩形。。。这样分是因为在这两者之内进行状态转移是互不相关的

sg[i]代表连续i个空矩形的sg值,其后继状态就是从左到右填充1个或连续4个矩形

#include <stdio.h>
#include <string.h>
const int MAX = 5000;
int sg[MAX];
bool flg[MAX], mmp[2][MAX];
int mex(int k)
{
	if (sg[k] != -1 ) return sg[k];
	memset(flg, 0, sizeof flg);
	int i, j;
	for ( i = 0; k-1-i>=i; i++)
	{
		int tmp = mex(i)^mex(k-i-1)^1;
		flg[tmp] = 1;
	}
	for (i = 0; k-2-i>=i; i++)
	{
		int tmp = mex(i)^mex(k-2-i);
		flg[tmp] = 1;
	}
	for (i = 0;;i++)
	{
		if (!flg[i])
		{
			sg[k] = i;
			break;
		}
	}
	return sg[k];
}
int main()   
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	int i, j, k;
	memset(sg, -1, sizeof sg);

	for (i = 1, sg[0] = 0; i< 4750; i++)	// 初始化
	{
		sg[i] = mex(i);
	}
	int t, n, m, cs = 0, x, y;
	int res = 0;
	scanf("%d", &t);
	while (t--)
	{
		res = 0;
		printf("Case %d: ", ++cs);
		scanf("%d%d", &n, &m);
		memset(mmp, 0, sizeof mmp);
		for (i = 0; i< m; i++)
		{
			scanf("%d%d", &x, &y);
			mmp[x-1][y-1] = 1;
		}
		mmp[0][n] = mmp[1][n] = 1;
		for (k= 0, i = 0; i<= n; i++)
		{
			j = 0;
			if (mmp[0][i]) j++;
			if (mmp[1][i]) j++;
			if (j)
				res ^= sg[k]^(j&0x1), k = 0;
			else 
				k++;
		}
		if (res) puts("Alice");
		else puts("Bob");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值