zoukankan      html  css  js  c++  java
  • 博弈论中的SG函数

    SG函数的定义:

    g(x) = mex ( sg(y) |y是x的后继结点 )

    其中mex(x)(x是一个自然是集合)函数是x关于自然数集合的补集中的最小值,比如x={0,1,2,4,6} 则mex(x)=3;

    什么是后继结点?

    所谓后继结点就是当前结点经过一个操作可以变成的状态。比如对于娶4石子游戏,假如每次可以取的数目是1,2,4,当前的石子数目也就是当前状态是5,那么5的后继结点就是{5-1, 5-2, 5-4}={4,3,1};

    如果5的三个后继结点的SG函数值分别为0,1,3,那么5的SG值就是集合{0,1,3}的补集的最小元素,也就是2。

    关于整个游戏的sg值之和sum,定义sum=sg1 ^ sg2 ^ sg3 ^ ……sgn.  其中^表示按位异或运算。

    结论:一个游戏的初始局面是必败态当且仅当sum=0。

    一篇非常好的关于SG值的论文:http://www.cnitblog.com/weiweibbs/articles/42735.html

    SG值打表模板:

    //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;
                }
            }
        }
    }

    HDU1848  

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=1848

    题意:取石子问题,一共有3堆石子,每次只能取斐波那契数个石子,先取完石子者胜利,问先手胜还是后手胜

    1. 可选步数为一系列不连续的数,用GetSG(计算) 
    2. 最终结果是所有SG值异或的结果 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=1001;
    //f[]  可以取走的石子数
    //sg[]   0~n的sg函数值
    //hash[]  mex{}
    int f[maxn],sg[maxn],hash[maxn];
    void getsg(int n)
    {
        memset(sg,0,sizeof(sg));
        for(int i=1;i<=n;i++)
        {
            memset(hash,0,sizeof(hash));
            for(int j=1;f[j]<=i;j++)
                hash[sg[i-f[j]]]=1;
            for(int j=0;j<=n;j++)
            {
                if(hash[j]==0)
                {
                    sg[i]=j;
                    break;
                }
            }
        }
    }
    int main()
    {
        int n,m,k;
        f[0]=f[1]=1;
            for(int i=2;i<=16;i++)
                f[i]=f[i-1]+f[i-2];
            getsg(1000);
        while(cin>>n>>m>>k)
        {
            if(!n&&!m&&!k)
                break;
            int sum=0;
            sum=sg[n]^sg[m]^sg[k];
            if(sum==0)
                cout<<"Nacci"<<endl;
            else
                cout<<"Fibo"<<endl;
        }
        return 0;
    }
    



  • 相关阅读:
    mina 实例(转载)
    Java NIO 转载
    解决 Tomcat reload WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but fail
    ECharts的使用相关参考---转
    转-——推荐几个web中常用的一些js图表插件
    (转)Log4J日志配置详解
    ~与~+的用法
    【转】sed 高级用法
    使用sed替换一行内多个括号内的值
    【转】 SED多行模式空间
  • 原文地址:https://www.cnblogs.com/wolf940509/p/6617117.html
Copyright © 2011-2022 走看看