打表:
//f[]:可以取走的石子个数
//sg[]:0~n的SG函数值
//hash[]:mex{}
int f[N],sg[N],hash[N];
void getSG(int n)
{
int i,j;
memset(sg,0,sizeof(sg));
for(i=1;i<=n;i++)
{
memset(hash,0,sizeof(hash));
for(j=1;f[j]<=i;j++)
hash[sg[i-f[j]]]=1;
for(j=0;j<=n;j++) //求mes{}中未出现的最小的非负整数
{
if(hash[j]==0)
{
sg[i]=j;
break;
}
}
}
}
搜索:
//注意 S数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合s的大小 S[i]是定义的特殊取法规则的数组
int s[110],sg[10010],n;
int SG_dfs(int x)
{
int i;
if(sg[x]!=-1)
return sg[x];
bool vis[110];
memset(vis,0,sizeof(vis));
for(i=0;i<n;i++)
{
if(x>=s[i])
{
SG_dfs(x-s[i]);
vis[sg[x-s[i]]]=1;
}
}
int e;
for(i=0;;i++)
if(!vis[i])
{
e=i;
break;
}
return sg[x]=e;
}
51nod 1070
在知道这是斐波那契博弈之前打表打错了,菜到变形.jpg
由于每次取的规则都有变化,所以要用特殊的记忆化搜索
正确的打表姿势:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<iomanip>
#include<cctype>
#include<stack>
using namespace std;
const int MAXN=1e6+5;
const int INF=1<<30;
const long long mod=1e9+7;
const double eps=1e-8;
#define ll long long
#define edl putchar('
')
#define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define FORLL(i,a,b) for(ll i=a;i<=b;i++)
#define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
#define mst(a) memset(a,0,sizeof(a))
#define mstn(a,n) memset(a,n,sizeof(a))
#define zero(x)(((x)>0?(x):-(x))<eps)
int sg[1005][1005];
int dfs(int x,int limit,int flag)//0 win 1lose
{
//cout<<x<<" "<<limit<<" "<<flag<<endl;
if(limit!=-1&&sg[x][limit]!=-1)
return sg[x][limit]^!flag;
if(limit!=-1&&x<=2*limit)
{
sg[x][limit]=flag;
return flag;
}
int a[5]={0,0},maxx=2*limit;
if(limit==-1)
maxx=x-1;
FOR(i,1,maxx)
{
a[dfs(x-i,i,!flag)]++;
}
if(a[flag]==0)
{
sg[x][limit]=!flag;
return !flag;
}
else
{
sg[x][limit]=flag;
return flag;
}
}
int main()
{
FOR(i,1,1000)
FOR(j,1,1000)
sg[i][j]=-1;
FOR(i,2,1000)
{
if(dfs(i,-1,0))
cout<<i<<endl;
}
}
顺便考虑了一下,把规则改成可以取三倍的情况(只要把搜索里的2*limit改成3*limit即可),得到了一个这样的数列:
2 3 4 6 8 11 15 21 29 40 55 76 105 145 200 276 381 526 726
看出规律为a[i]=a[i-1]+a[i-4],至于前四项似乎看不出规则。