博弈论(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;
}

 

posted @ 2012-04-20 20:06  龙杉老师  阅读(1328)  评论(0编辑  收藏  举报