码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj-1188 分裂游戏

时间:2015-08-04 13:44:06      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:bzoj   博弈论   sg函数   

题意:

有n堆石头,编号为1-n;

每次操作为选择三个堆,i<j<=k;

取走i中的一个石子并在j,k两堆都放入一个;

不能操作的人输,求先手能否必胜;

若能则输出第一步的字典序最小方案和方案数;


题解:
博弈论的题目一般就是组合游戏加SG函数;

但是稍微一考虑却发现各个石头堆不是独立的,不能直接上组合游戏;

所以这题是HNOI的题,考虑每个石头作为一个游戏;

会发现这样就是独立的游戏了!

那么定义SG函数f[x]表示离第n堆还有x堆的一颗石头的SG值;

显然f[0]=0,枚举比x小的i,j就是x的后继状态,打出了SG函数表;

然后对每个堆中的石头求异或和,求和不为0则先手必胜;

输出方案啥的暴力枚举O(n^3)可以解决;


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 50
using namespace std;
int f[N],a[N];
bool hash[N];
int sg(int x)
{
	memset(hash,0,sizeof(hash));
	for(int i=0;i<x;i++)
		for(int j=0;j<=i;j++)
			hash[f[i]^f[j]]=1;
	for(int i=0;;i++)
	{
		if(!hash[i])
		{
			f[x]=i;
			break;
		}
	}
}
void init()
{
	for(int i=1;i<=21;i++)
		sg(i);
}
int main()
{
	int c,T,n,m,i,j,k,l,ans,cnt;
	bool flag;
	init();
	scanf("%d",&T);
	for(c=1;c<=T;c++)
	{
		scanf("%d",&n);
		for(i=1;i<=n;i++)
			scanf("%d",a+i);
		for(i=1,ans=0;i<=n;i++)
			if(a[i]&1)
				ans^=sg(n-i);
		if(ans==0)
		{
			printf("-1 -1 -1\n0\n");
			continue;
		}
		for(i=1,flag=0,cnt=0;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
			{
				for(k=j;k<=n;k++)
				{
					if((ans^f[n-i]^f[n-j]^f[n-k])==0)
					{
						if(!flag)
						printf("%d %d %d\n",i-1,j-1,k-1),flag=1;
						cnt++;
					}
				}
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}


bzoj-1188 分裂游戏

标签:bzoj   博弈论   sg函数   

原文地址:http://blog.csdn.net/ww140142/article/details/47273213

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!