[UVA10561] Treblecross && 博弈 SG函数

本文探讨了如何解决复杂SG函数的问题,并通过记忆化优化提高效率。重点介绍了枚举策略、SG函数的计算过程及判断胜负的条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一次写这么复杂的SG函数 Orz 还好记忆化比较好写

输出方案的话就直接枚举第一个X放在哪里

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define SF scanf
#define PF printf
#define max(a, b) ((a) < (b) ? (b) : (a))
using namespace std;
typedef long long LL;
const int MAXN = 200;
int SG[MAXN+10], Len, CNT, Step[MAXN+10];
char s[MAXN+10];bool Now_Win()
{
	for(int i = 0; i < Len - 2; i++) 
		if(s[i] == 'X' && s[i+1] == 'X' && s[i+2] == 'X')
			return true;
	return false;
}
int getSG(int x)
{
	bool vis[MAXN+10];
	if(~SG[x]) return SG[x];
	if(x == 0) return SG[x] = 0;
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i <= x; i++) {
		int sg = getSG(max(0, i-3)) ^ getSG(max(0, x-i-2));
		vis[sg] = true;
	}
	for(int i = 0; i < MAXN; i++) if(!vis[i]) return SG[x] = i;
	return -1;
}
bool Will_Win()
{
	for(int i = 0; i < Len; i++)
		if(s[i] == '.') {
			s[i] = 'X';
			if(Now_Win()) { s[i] = '.'; return false;  }
			s[i] = '.';
		}
	int sg = 0, space = 0;
	for(int i = 0; i < Len; i++)
		if(s[i] == 'X' || (i && s[i-1] == 'X') || (i > 1 && s[i-2] == 'X') || (i < Len-1 && s[i+1] == 'X') || (i < Len-2 && s[i+2] == 'X'))
		{
			sg ^= getSG(space);
			space = 0;
		}
		else space++;
	sg ^= getSG(space);
	return sg == 0;
}
void solve()
{
	CNT = 0;
	Len = strlen(s);
	for(int i = 0; i < Len; i++) 
	{
		if(s[i] == 'X') continue;
		s[i] = 'X';
		if(Now_Win() || Will_Win()) Step[++CNT] = i + 1;
		s[i] = '.';
	}
}
int main()
{
	memset(SG, -1, sizeof(SG));
	int T; SF("%d", &T); while(T--) {
		SF("%s", s);
		solve();
		if(CNT) {
			PF("WINNING\n%d", Step[1]);
			for(int i = 2; i <= CNT; i++) PF(" %d", Step[i]);
			puts("");
		}
		else PF("LOSING\n\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值