传送门
题意
n n n个格子,每次每个人可以在一个空闲格子放上一个×
当一个人操作完后出现连续三个叉时就赢了,问先手的胜负状况
我们在 p o s pos pos位置放了×后,相当于把局面分成了两半
因为 p o s − 1 , p o s − 2 , p o s + 1 , p o s + 2 pos-1,pos-2,pos+1,pos+2 pos−1,pos−2,pos+1,pos+2都不能放格子了
一旦放了自己就输了
所以局面分成长度为 m a x ( 0 , p o s − 3 ) max(0,pos-3) max(0,pos−3)和长度为 m a x ( 0 , n − p o s − 2 ) max(0,n-pos-2) max(0,n−pos−2)的两个局面
那么原问题可以简化为,不能操作的人就算输
那么当长度为零时是不能操作的,所以 s g [ 0 ] = 0 sg[0]=0 sg[0]=0
那么就可以记忆化搜索了
感觉这种定义 s g sg sg的形式比较巧妙
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 2009;
int n,sg[maxn];
int solve(int n)
{
if( sg[n]!=-1 ) return sg[n];
bool ok[maxn]; memset( ok,0,sizeof ok );
for(int i=1;i<=n;i++) ok[solve(max(0,i-3))^solve(max(0,n-i-2))] = 1;
for(int i=0;i<=n;i++)
if( ok[i]==0 ) return sg[n] = i;
}
int main()
{
memset( sg,-1,sizeof sg );
sg[0] = 0;
while( cin >> n )
{
if( solve(n) ) cout << "1\n";
else cout << "2\n";
}
}