• HIT暑期集训 博弈


    学长的博弈总结博客 orz

    博弈SG函数模板

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 1005 
    using namespace std;
    int f[maxn],sg[maxn],mex[maxn];
    void get_f(int n)
    {
        int i;
        f[1]=1;f[2]=2;
        for (i=3;f[i-1]<n;i++) f[i]=f[i-1]+f[i-2];
    }
    void get_sg(int n)
    {
        int i,j;
        memset(sg,0,sizeof(sg));
        for (i=1;i<=n;i++)
        {
            memset(mex,0,sizeof(mex));
            for (j=1;f[j]<=i;j++)
                mex[sg[i-f[j]]]=1;
            for (j=0;j<=n;j++)
                if (!mex[j]) break;
            sg[i]=j;
        }
    }
    int main()
    {
        int m,n,p;
        get_f(1000);
        get_sg(1000);
        while (scanf("%d%d%d",&m,&n,&p)!=EOF && m!=0)
        {
            if (sg[m]^sg[n]^sg[p]) printf("Fibo
    ");
            else printf("Nacci
    ");
        }
        return 0;
    }
    博弈SG模板,HDU1848

    C    HDU 1404

    因为输入的字符串只有6位,就可以把它当作一个6位整数x。

    从(先手)必败状态x开始,可进行的操作有①在x的某一位上加上一个数(加上后该位不超过9)②当x不足6位,可以在x后面加0(即乘以10或100...)

    这样由必败状态推出的所有状态均为必胜状态。

    预处理1000000以内的所有数的胜败状态,每次输入时根据对应值输出即可。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 1000005 
    using namespace std;
    int sg[maxn];
    char s[12];
    void get_sg(int x)
    {
        int i,j,y=x,l=0,now,k;
        while (y)
        {
            l++;y=y/10;
        }
        for (i=1,k=1;i<=l;i++,k=k*10)
        {
            now=x/k%10;
            y=x;
            for (j=now;j<9;j++)
            {
                y+=k;
                sg[y]=1;
            }
        }
        y=x;
        for (k=1;l<6;l++,k=k*10)
        {
            y=y*10;
            for (i=0;i<k;i++) sg[y+i]=1;
        }
    }
    int main()
    {
        int i,n,m,len,x;
        sg[0]=1;
        for (i=1;i<1000000;i++)
            if (!sg[i]) get_sg(i);
        while (scanf("%s",s)!=EOF)
        {
            if (s[0]=='0') printf("Yes
    ");
            else 
            {
                x=0;
                len=strlen(s);
                for (i=0;i<len;i++) x=x*10+s[i]-'0';
                if (sg[x]) printf("Yes
    ");
                else printf("No
    ");
            }    
        }
        return 0;
    }
    View Code

    E    HDU 3980

    第一个人先涂m个,把n长的链变为n-m长的环,每次的结果等于涂色后分出的两端的答案的异或和。据此就可递归求出sg了。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 1005 
    using namespace std;
    int sg[maxn],mex[maxn],n,m;
    int findsg(int x)
    {
        if (sg[x]!=-1) return sg[x];
        if (x<m) return sg[x]=0;
        int i;
        memset(mex,0,sizeof(mex));
        for (i=m;i<=x;i++)
            mex[findsg(i-m)^findsg(x-i)]=1;
        for (i=0;;i++)
            if (!mex[i]) break;
        return sg[x]=i;
    }
    int main()
    {
        int T,t,i;
        scanf("%d",&T);
        for (t=1;t<=T;t++)
        {
            scanf("%d%d",&n,&m);
            printf("Case #%d: ",t);
            if (n<m) printf("abcdxyzk
    ");
            else 
            {
                n=n-m;
                memset(sg,-1,sizeof(sg));
                for (i=0;i<=n;i++) sg[i]=findsg(i);
                if (sg[n]) printf("abcdxyzk
    ");
                else printf("aekdycoin
    ");
            }
        }
        return 0;
    }
    View Code

    F    CodeForces 1147C

    设这n堆石子中,石子数量最少为x,cnt数组记录不同石子数量在n堆石子中出现的次数。

    则若cnt[x]<=n/2,此时必胜;若cnt[x]>n/2,此时必败,因为cnt[x]<=n/2可以通过取石子的方式转移至该状态。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 55 
    #define inf 99999999
    using namespace std;
    int cnt[maxn];
    int main()
    {
        int i,x,n,re=inf;
        scanf("%d",&n);
        for (i=1;i<=n;i++) 
        {
            scanf("%d",&x);
            cnt[x]++;
            re=min(re,x);
        }
        if (cnt[re]<=n/2) printf("Alice
    ");
        else printf("Bob");
        return 0;
    }
    View Code

    G    CodeForces 936B

    H    POJ 1704

    I    POJ 2425

    题意:给一个图,图中有m条有向边,给出几个棋子的初始位置,游戏双方轮流沿着边移动这几个棋子,最后无法移动这几个棋子的人输。

    思路:把每个棋子看作一个子游戏,通过记忆化搜索求出sg数组后,将每个棋子的答案异或就是最终答案。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define maxn 1005 
    using namespace std;
    int sg[maxn],mp[maxn][maxn],n,ans;
    int dfs(int x)
    {
        if (sg[x]!=-1) return sg[x];
        int mex[maxn];
        memset(mex,0,sizeof(mex));
        int i;
        for (i=0;i<n;i++)
            if (mp[x][i]) mex[dfs(i)]=1;
        for (i=0;;i++) 
            if (!mex[i]) break;
        return sg[x]=i;
    }
    int main()
    {
        int m,x,i;
        while (scanf("%d",&n)!=EOF)
        {
            memset(mp,0,sizeof(mp));
            memset(sg,-1,sizeof(sg));
            for (i=0;i<n;i++)
            {
                scanf("%d",&m);
                if (m==0) sg[i]=0;
                while (m--)
                {
                    scanf("%d",&x);
                    mp[i][x]=1;
                }
            }
            for (i=0;i<n;i++)
            { 
                sg[i]=dfs(i);
            }
            while (scanf("%d",&m)!=EOF && m!=0)
            {
                ans=0;
                while (m--)
                {
                    scanf("%d",&x);
                    ans=ans^sg[x];
                }
                if (ans) printf("WIN
    ");
                else printf("LOSE
    ");
            }
        }
        return 0;
    }
    View Code

     (补充一个网上找到讲博弈论基础的博客https://www.cnblogs.com/lfri/p/10662291.html

  • 相关阅读:
    理解和配置 Linux 下的 OOM Killer
    ARM各种版本号知识以及型号的发展(三星为例)
    GCC 编译使用动态链接库和静态链接库
    insmod module_param 模块参数
    cgic 写CGI程序
    嵌入式应用中CGI编程中POST、GET及环境变量详解
    CGI技术原理
    h264 流、帧结构
    LocalDate、LocalDateTime与timestamp、Date的转换
    Java8中 Date和LocalDateTime的相互转换
  • 原文地址:https://www.cnblogs.com/lsykk/p/13594583.html
Copyright © 2020-2023  润新知