关于SG函数

本文分享了作者在学习博弈论及其核心概念SG函数过程中的心得体验,详细介绍了使用SG函数解决经典取石子问题的方法,并提供了两种实现方案——递归深度优先搜索(DFS)与预处理(打表法)。通过具体题目hdu1536、hdu1848和hdu3975的解析,展示了不同场景下SG函数的应用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一年前的博文了。时间过得真快啊~~~现在又不会SG了。        

 一直觉得博弈是一个很是神秘的东西,现在在看博弈,觉得很是有趣,尤其是SG函数,昨天今天做了几道题,尤其 是上周的多校给了我很多不一样的东西。开始的时候做的是HDU上的两道取石子的题目。基本上都是给你几堆石子然后有规定你只能取几颗什么的。多校的那道题我按同样的思路来写WA掉了,现在才终于理解所谓的前继后继。明明是很明显的一个点总是会出现在我视线的盲区。对于其他概念的理解也是这样,让我觉得小不爽,但是好歹是对SG的了解更加深了一步。。噢~~~~附上hdu上三道题的解法,其中两道都分别用DFS和打表写了一遍~~

hdu1536:

(dfs版)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s[110],a[110][110],min,k,l,sg[10010];
int sgfun(int n){
    int i,mex[101];
    memset(mex,0,sizeof(mex));
        for(i=1;i<=k;i++){
            if(n>=s[i]){
                if(sg[n-s[i]]==-1)
                sg[n-s[i]]=sgfun(n-s[i]);
                mex[sg[n-s[i]]]=1;
            }
            else
            break;
        }
        for(i=0;mex[i];i++);
        return i;

}
main(){
    int i,j,ans;
    memset(sg,-1,sizeof(sg));
    while(scanf("%d",&k)!=-1 && k){
        //printf("pp\n");
        memset(sg,-1,sizeof(sg));
        for(i=1;i<=k;i++){
            scanf("%d",&s[i]);
        }
        //printf("pp\n");
        sort(s+1,s+k+1);
        scanf("%d",&l);
        //ans=1;
        //printf("pp\n");
        for(i=1;i<=l;i++){
            scanf("%d",&a[i][0]);
            //printf("pp\n");
            for(j=1;j<=a[i][0];j++){
                scanf("%d",&a[i][j]);
                //memset(mex,0,sizeof(mex));
                if(sg[a[i][j]]==-1)
                    sg[a[i][j]]=sgfun(a[i][j]);
                if(j==1){
                ans=sg[a[i][j]];
                }
                else{
                ans^=sg[a[i][j]];
                }
            }
            if(ans)
                printf("W");
            else
                printf("L");
        }
        printf("\n");
    }
}

(打表版)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int s[110],a[110][110],min,k,l,mex[10010],sg[10010];
void sgfun(){
    int i,mex[101],j,p;
    sg[0]=0;
    for(i=1;i<10001;i++){
        j=1;
        memset(mex,0,sizeof(mex));
        while(j<=k && i>=s[j]){
            mex[sg[i-s[j]]]=1;
            j++;
        }
        j=0;
        while(mex[j]){
            j++;
        }
        sg[i]=j;
    }

}
main(){
    int i,j,ans;
    //memset(sg,-1,sizeof(sg));
    //sgfun();
    while(scanf("%d",&k)!=-1 && k!=0){
        //printf("pp\n");
        //memset(sg,-1,sizeof(sg));
        for(i=1;i<=k;i++){
            scanf("%d",&s[i]);
        }
        //printf("pp\n");
        sort(s+1,s+k+1);
        sgfun();
        scanf("%d",&l);
        //ans=1;
        //printf("pp\n");
        for(i=1;i<=l;i++){
            scanf("%d",&a[i][0]);
            //printf("pp\n");
            ans=0;
            for(j=1;j<=a[i][0];j++){
                scanf("%d",&a[i][j]);
                //memset(mex,0,sizeof(mex));
                //if(sg[a[i][j]]==-1)
                    //sg[a[i][j]]=sgfun(a[i][j]);
                ans^=sg[a[i][j]];
            }
            if(ans)
                printf("W");
            else
                printf("L");
        }
        printf("\n");
    }
}

hdu1848:

(打表版)

#include<cstdio>
#include<cstring>
using namespace std;
int mex[1001],sg[1001],f[20];
void fibo(){
    int i;
    f[0]=1;f[1]=1;
    for(i=2;i<=16;i++)
    f[i]=f[i-1]+f[i-2];
}
/*int sgfun(int n){
    int i;    
    memset(mex,0,sizeof(mex));
    for(i=1;i<=16;i++){
        if(n>=f[i]){
            if(sg[n-f[i]]==-1)
            sg[n-f[i]]=sgfun(n-f[i]);
            mex[sg[n-f[i]]]=1;
        }
        else
        break;
    }
    for(i=0;mex[i];i++);
    return i;
    
}*/
void sgfun(){
    int i,mex[101],j;
    sg[0]=0;
    for(i=1;i<1001;i++){
        j=1;
        memset(mex,0,sizeof(mex));
        while(j<=16 && i>=f[j]){
            mex[sg[i-f[j]]]=1;
            j++;
        }
        j=0;
        while(mex[j]){
            j++;
        }
        sg[i]=j;
    }

}

main(){
    int n,m,p,ans;
    fibo();
    memset(sg,-1,sizeof(sg));
    sgfun();
    while(scanf("%d%d%d",&n,&m,&p)!=-1 && !(n==0 && m==0 && p==0)){
        //if(sg[n]==-1)
        //sg[n]=sgfun(n);
        //if(sg[m]==-1)
        //sg[m]=sgfun(m);
        //if(sg[p]==-1)
        //sg[p]=sgfun(p);
        ans=sg[n];
        ans^=sg[m];
        ans^=sg[p];
        //printf("%d %d %d\n",sg[n],sg[m],sg[p]);
        //printf("%d\n",ans);
        if(ans)
        printf("Fibo\n");
        else
        printf("Nacci\n");
    }
}

(dfs)

#pragma comment(linker, "/STACK:1024000000,1024000000")


#include<cstdio>
#include<cstring>
using namespace std;
int sg[1001],f[20];
void fibo(){
    int i;
    f[0]=1;f[1]=1;
    for(i=2;i<=16;i++)
    f[i]=f[i-1]+f[i-2];
}
int sgfun(int n){
    int i,mex[1001];    
    memset(mex,0,sizeof(mex));
    for(i=1;i<=16;i++){
        if(n>=f[i]){
            if(sg[n-f[i]]==-1)
            sg[n-f[i]]=sgfun(n-f[i]);
            mex[sg[n-f[i]]]=1;
        }
        else
        break;
    }
    for(i=0;mex[i];i++);
    return i;
    
}
main(){
    int n,m,p,ans;
    fibo();
    memset(sg,-1,sizeof(sg));
    //sgfun();
    while(scanf("%d%d%d",&n,&m,&p)!=-1 && !(n==0 && m==0 && p==0)){
        if(sg[n]==-1)
        sg[n]=sgfun(n);
        if(sg[m]==-1)
        sg[m]=sgfun(m);
        if(sg[p]==-1)
        sg[p]=sgfun(p);
        ans=sg[n];
        ans^=sg[m];
        ans^=sg[p];
        //printf("%d %d %d\n",sg[n],sg[m],sg[p]);
        //printf("%d\n",ans);
        if(ans)
        printf("Fibo\n");
        else
        printf("Nacci\n");
    }
}

hdu3975



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值