模板:SG函数

解题模型:

1.把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。
即SG(G)=SG(G1)^ SG(G2)^ … ^Sg(Gn)。

2.分别考虑每一个子游戏,计算其SG值。

SG值的计算方法:(重点)

   a.可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1)(Bash game)。

   b.可选步数为任意步,SG(x) = x(Nim game)。

   c.可选步数为一系列不连续的数,用模板计算。

结论:

1.当SG[x] = 0时,x为必败状态。

2.当SG[x] > 0时,x为必胜状态。

int f[N],SG[MAXN],S[MAXN];//f[] - 可改变当前状态 的方式   S[] - 当前状态的后继状态集合
//打表
void getSG(int n) {
	int i,j;
	memset(SG,0,sizeof(SG));
	for(i = 1; i <= n; i++) { 
		memset(S,0,sizeof(S));
		for(j = 0; f[j] <= i && j <= N; j++)
			S[SG[i-f[j]]] = 1;//S[]数组来保存当前状态的后继状态集合
		for(j = 0;; j++) if(!S[j]) {//模拟mex运算
				SG[i] = j;
				break;
			}
	}
}
//注意 f数组要按从小到大排序 SG函数要初始化为-1 对于每个集合只需初始化1遍
//n是集合f的大小 f[i]是定义的特殊取法规则的数组
int f[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>=f[i])
        {
            SG_dfs(x-f[i]);
            vis[SG[x-f[i]]]=1;
        }
    }
    int e;
    for(i=0;;i++)
        if(!vis[i])
        {
            e=i;
            break;
        }
    return SG[x]=e;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值