Luogu P10501 Cutting Game 题解

P10501 Cutting Game

博弈论经典题目,考虑使用 SG 函数解决。

但是这一题和有向图游戏的定义不同,在有向图游戏不能操作者判负,而这一题中操作出某个状态者判胜。因此,我们需要进行转化。经典做法是往前推直到推出必败态作为有向图游戏的终点。

我们考虑什么样的情况可以剪出 1×1 的纸条,显然,当且仅当在 1×nn×1 的纸条上可以剪出 1×1 的纸条。因此,这种情况下是先手必胜态。

往前推出必败态,就是要找到一个只能剪出 1×nn×1 的纸条的状态。不难发现在 2×2,2×3,3×2 的纸条中都只能剪出 1×nn×1 的纸条,因此它们是必败态。以它们作为有向图游戏的终点,即可按照有向图游戏的方式处理。

我们考虑枚举每个状态在哪一行或者哪一列剪开,之后就是两个剪纸子问题,求出它们的 SG 函数的值后用有向图游戏和异或起来就是当前状态的一个后继状态的 SG 函数值,求 mex 就行了。

注意每一步不会直接剪出 1×nn×1 的纸条,因为会使对手直接获胜,所以代码实现时需要注意边界条件。下面给出转移式。

sg(n,m)=mex{{sg(i,m)sg(ni,m)2i<n1}{sg(n,i)sg(n,mi)2i<m1}}

使用记忆化搜索预处理实现。

#include <bits/stdc++.h>
using namespace std;
long long n,m,x[300000],sg[300][300];
bool vis[300][300];
long long dfs(long long n,long long m)
{
	if(n==2&&m==2)return 0;
	if(n==2&&m==3)return 0;
	if(n==3&&m==2)return 0;
	if(vis[n][m])return sg[n][m];
	vis[n][m]=1;
	for(int i=2;i<n-1;i++)x[dfs(i,m)^dfs(n-i,m)]=1;
	for(int i=2;i<m-1;i++)x[dfs(n,i)^dfs(n,m-i)]=1;
	long long mex=0;
	while(x[mex])mex++;
	for(int i=2;i<n-1;i++)x[dfs(i,m)^dfs(n-i,m)]=0;
	for(int i=2;i<m-1;i++)x[dfs(n,i)^dfs(n,m-i)]=0;
	return sg[n][m]=mex;
}
 
int main()
{
	for(int i=2;i<=200;i++)
	    for(int j=2;j<=200;j++)dfs(i,j);
	while(scanf("%lld%lld",&n,&m)!=-1)
	   {
	   	if(sg[n][m])printf("WIN\n");
	   	else printf("LOSE\n");
	   }
	return 0;
} 
posted @   w9095  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示