博弈论(2)

 

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

    

博弈论(2)

解:

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

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

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

博弈论(2)

 

 

 

函数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;

}

 

你可能感兴趣的:(博弈论(2))