AcWing 219. 剪纸游戏

蒟蒻的第一道博弈论题目大概

游戏开始时,是一个(N*M)的矩形网格纸。但是在游戏过程中会被分割。我们把每一个矩形网格纸都当做一个”游戏“,那么我们求的就是有向图游戏的和

那么现在就有一个问题:

不能行动的局面是(1*1),此时行动者判负((Update:)应该是判胜,打错了),这与有向图游戏不符合

我们思考(1*1)局面能够怎么得出,显然势必会经过(1*X,X*1,2*2,2*3,3*2)这几个局面

容易看出:(1*X)(X*1)是给对手送分的行为

那么得到(1*1)局面就必然经过(2*2,2*3,3*2)这三个局面之一

单独看着三个局面,容易看出先手必败

那么我们可以把这三种状态当做有向图游戏的无法移动状态

接下来的问题就是考虑如何去移动了,我们可以枚举把这张剪枝剪成两部分,这两部分就是两个“子剪纸游戏”,二者的SG值执行(xor)运算,就得到了这个行动之后局面的(SG)值,对所有的合法行动产生的局面构成的集合执行(mex)运算,就得到了这个(N*M)的矩形网格纸的(SG)函数值,从而根据有向图游戏的和的知识

  • 如果(SG)函数值大于(0),必胜
  • 如果(SG)函数值等于(0),必败
/*
@ author:pyyyyyy
-----思路------

-----debug-------

*/
#include<bits/stdc++.h>
using namespace std;
const int N=220;
int sg[N][N];
int n,m;
int SG(int x,int y)
{
	int f[N];
	memset(f,0,sizeof(f));//集合
	if(sg[x][y]!=-1) return sg[x][y];
	for(int i=2;i<=x-2;++i) f[SG(i,y)^SG(x-i,y)]=1;
	for(int i=2;i<=y-2;++i) f[SG(x,i)^SG(x,y-i)]=1;
	int p=0;
	while(f[p]) ++p;//mex运算 
	return sg[x][y]=p;
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	for(int i=1;i<=N;++i)
		for(int j=1;j<=N;++j)
			sg[i][j]=-1;
	sg[2][2]=0,sg[2][3]=0,sg[3][2]=0; 
	while(cin>>n>>m)
	{
		cout<<(SG(n,m)?"WIN":"LOSE");
		cout<<'
';
	}
	return 0;
}


原文地址:https://www.cnblogs.com/pyyyyyy/p/12761647.html