• 博弈论(2)


               甲乙两人面对若干排石子,其中每一排石子的数目可以任意确定。例如图所示的初始局面:共n=3排,其中第一排的石子数a1=7,第二排石子数a2=3,第三排石子数a3=3。两人轮流按下列规则取走一些石子,游戏的规则如下:每一步必须从某一排中取走两枚石子;这两枚石子必须是紧紧挨着的;如果谁无法按规则取子,谁就是输家。

        

    解:

      用符号#S,表示局面S所对应的二进制数。

      用符号$(x),表示局面(x)下一步所有可能出现的局面的集合。

     定义集合g(x):设$(x)={S1, S2, …, Sk},则g(x)={#S1, #S2, …, #Sk}

     

     

    函数f满足要求的一个充分条件

    f(a1)不属于集合g(a1)。

    集合g(a1)包含集合{0, 1, …, f(a1)–1}。

    如果g(a1)={0, 1, 2, 5, 7, 8, 9},则f(a1)=3,满足要求。

     

    用大写字母N表示非负整数集,即N={0, 1, 2, …}。

    令N为全集,集合G(x)表示集合g(x)的补集。

     

    定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。

    设局面S=(a1, a2, …, an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。

    若#S=0,则S负;若#S≠0,则S胜。

     

    游戏C的f值:

    g(0)={},G(0)={0, 1, …},f(0)=0;

    g(1)={},G(1)={0, 1, …},f(1)=0;

    g(2)={#(0)}={f(0)}={0},G(2)={1, 2, …},f(2)=1;

    g(3)={#(1)}={f(1)}={0},G(2)={1, 2, …},f(3)=1;

    g(4)={#(2), #(1, 1)}={f(2), f(1)+f(1)}={1, 0},G(4)={2, 3, …},f(4)=2;

    g(5)={#(3), #(1, 2)}={f(3), f(1)+f(2)}={1, 1},G(5)={0, 2, 3, …},f(5)=0;

    g(6)={#(4), #(1, 3), #(2, 2)}={2, 1, 0},G(6)={3, 4, …},f(6)=3;

    g(7)={#(5), #(1, 4), #(2, 3)}={0, 2},G(7)={1, 3, 4, …},f(7)=1;

    图2所示的局面S=(7, 3, 3),有#S=f(7)+f(3)+f(3)=1+1+1=1,故S胜。

    游戏C的初始局面S=(3, 4, 6),有#S=1+2+3=01+10+11=0,故S负。

     

    此类搏弈游戏的一般性解法:
    用一个n元组(a1, a2, …, an),来描述游戏过程中的一个局面。
    用符号#S,表示局面S所对应的二进制数。
    用符号$(x),表示局面(x)的下一步所有可能出现的局面的集合。
    定义集合g(x):设$(x)={S1, S2, …, Sk},则g(x)={#S1, #S2, …, #Sk}。  
    令非负整数集为全集,集合G(x)表示集合g(x)的补集。
    定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。
    设局面S=(a1, a2, …, an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。
    若#S≠0,则先行者有必胜策略;若#S=0,则后行者有必胜策略。
     
    实现的一个代码如下:

    #include<iostream>
    using namespace std;
    #include<stdlib.h>
    int cmp(const void *a,const void *b)
    {
        return *(int *)a-*(int *)b;
    }
    int f[1000]={0,0,1,1};//初始化前4个
    int g[500],c[1000];
    int main()
    {
        int i,j,k,m,n,s;
        for(i=4;i<=1000;i++)
        {
            m=0;
            for(j=1;j<=i/2;j++)
            {
                g[m++]=f[j-1]^f[i-j-1];
            }
            qsort(g,m,sizeof(g[0]),cmp);//排序    
            for(k=0;;k++)
            if(g[k]!=k)//找其补集的最小值
            {
                f[i]=k;//找到f[i]
                break;
            }
            //printf("a[%d]=%d\n",i,a[i]);
        }
        while(scanf("%d",&n)!=EOF&&n)
        {
            for(i=0;i<n;i++)
             cin>>c[i];
            s=0;
            for(i=0;i<n;i++)
             s=s^f[c[i]];
            if(s==0)printf("先取者输\n");
            else printf("先取者赢\n");
        }
        
        return 0;
    }
  • 相关阅读:
    Leetcode 3. Longest Substring Without Repeating Characters/ 4. Median of Two Sorted Arrays[二分]
    最大流算法思想和理论的简单理解
    数值线性代数实验-共轭梯度法
    运筹学上机实验
    HDU 1542 Atlantis[扫描线]
    数值实验-高斯消元LU分解
    PAT 1143-Lowest Common Ancestor (30) 二叉树还原
    L2-006. 树的遍历
    hdu-3038 How Many Answers Are Wrong[并查集]
    poj-3253 Fence Repair[霍夫曼树]
  • 原文地址:https://www.cnblogs.com/hsqdboke/p/2459796.html
Copyright © 2020-2023  润新知