UVA 10561 Treblecross游戏(Nim博弈)

题目:https://vjudge.net/problem/UVA-10561

由于禁区内谁放谁输,所以禁区之外的一段一段分成了很多子游戏。

子游戏g(0)=0,g(1)=g(2)=g(3)=1,超过3以后就可以分成子游戏了,比如连续4个格子的,若在最左边放一个。

那么该格子可以影响最左边的3个格子,只有最右边的一个格子不受影响,所以g(4)=mex{g(x-3),g(x-4)}=2...依次类推

注意,当连续格子数大于5个得时候,要考虑子游戏情况。例如连续的6个格子,若放置的格子影响的是后5个格子,

则mex中有一项为g(1)xor g(x-6)。

最终,可以计算出g(x)函数,利用Nim和可求得结果。

#include<bits/stdc++.h>
using namespace std;
#define maxn 205

int g[maxn];
int vis[maxn],win[maxn],lis[maxn];
int a[maxn],n;
char now[maxn];
void caculate(){
	int j;
	g[0]=0,g[1]=g[2]=g[3]=1;
	g[4]=g[5]=2;
	for(int i=6;i<=maxn;i++){
		memset(vis,0,sizeof(vis));
		vis[g[i-3]]=vis[g[i-4]]=vis[g[i-5]]=1;
		for(int j=1;j+5<=i-j;j++)
		vis[g[j]^g[i-j-5]]=1;
		for( j=0;vis[j];j++) ;
		g[i]=j;
	}
}

bool check(){
	int i, j, c, nim_sum=0;
	memset(a,0,sizeof(a));
	for(i=2;i<n;i++)if(now[i]==now[i-1] and now[i]==now[i+1] and now[i]=='X')return true;
	for(i=2;i<n;i++)
	{
		c=(now[i-1]=='X')+(now[i]=='X')+(now[i+1]=='X');
		if(c==2)return false;
	}
for(i=1;i<=n;i++)
		if(now[i]=='X')
			for(j=0;j<3;j++)
			{
				if(i+j<=n)a[i+j]=1;
				if(i-j>0)a[i-j]=1;
			}
	
	for(int i=1;i<=n;i=j+1){
		if(a[i]) {j=i;continue;}
		else{
			for(;a[j+1]==0 and j<n;j++) ;
			nim_sum^=g[j+1-i];
		}
	
}
	return nim_sum==0;


}


int main(){
	int i,j,t,a=0;
	caculate();
	scanf("%d",&t);
	while(t--){
		scanf("%s",now+1);
		a=0;
		n=strlen(now+1);
		memset(win,0,sizeof(win));
		for(int i=1;i<=n;i++)
		if(now[i]=='.'){
			now[i]='X';
			if(check())
			win[++a]=i;
			now[i]='.';
		}
		
		if(win[1]) 
		{   
			printf("WINNING\n%d",win[1]);
			for(int i=2;win[i];i++)
			printf(" %d",win[i]);
		}
	
		if(win[1]==0) printf("LOSING\n");
		putchar(10);
	}

}
发布了60 篇原创文章 · 获赞 62 · 访问量 1361

猜你喜欢

转载自blog.csdn.net/weixin_43568895/article/details/104065632
今日推荐