取石子游戏

来源:互联网 发布:js判断是否为json对象 编辑:程序博客网 时间:2024/05/16 16:13
 在百度空间上看到一篇文章,颇有瑕疵及令人费解之处,我一定程度上做了修改和解释。怕以后可能会用到,于是转到我校内来了。

    有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可。两个人轮流从堆中取物体若干,规定最后取光物体者取胜。这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理。下面我们来分析一下要如何才能够取胜。

(一)巴什博奕(Bash Game):只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。

    显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=m+1r+s,(r为任意自然数,0sm+1),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。

    可以归结为:

    s=0,先手为负;

    s0,先手为胜。

    这个游戏还可以有一种变相的玩法:两个人轮流报数,每次至少报一个,最多报十个,谁能报到100者胜。

 

(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

    这种情况下是颇为复杂的。我们用(akbk)(ak bk ,k=012...,n)表示两堆物品的数量并称其为局势,如果甲面对(00),那么甲已经输了,这种局势我们称为奇异局势。(但此处关于奇异局势的定义不不是很好,我们可以这样理解:)前几个奇异局势是:(00)、(12)、(35)、(47)、(610)、(813)、(915)、(1118)、(1220)。

    可以看出,a0=b0=0,ak是未在前面出现过的最小自然数, bk= ak + k,(为什么ak只能是未在前面出现过的自然数,假使ak在前面出现过,那么必可减少bk的值使其变为前面出现过的奇异局势,从而得到的(ak,bk)不是奇异局势。另外如何保证ak为前面没有出现过的最小自然数时(ak, ak + k)一定是奇异局势?这是由规定的物品的取法决定的,规定每次同时从两堆中取同样多的物品或每次至少取一个,多者不限。那么的话无法只经过一次操作将这个局势变为奇异局势,而下面的三个性质说明了遵循正确的取法可以用两次取法将此局势变为奇异局势,那么很显然(ak, ak + k)就应该是奇异局势。事实上本文中关于奇异局势的定义并不完善,或者说并不足够好,因此可能我这儿说明的文字并不严密并不容易理解,但正确性应该是没有问题的。)奇异局势有如下三条性质:

    1。任何自然数都包含在一个且仅有一个奇异局势中。

    由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1。所以性质1。成立。

    2。任意操作都可将奇异局势变为非奇异局势。

    事实上,若只改变奇异局势(akbk)的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。如果使(akbk)的两个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。

    3。采用适当的方法,可以将非奇异局势变为奇异局势。

    假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(00);如果a = akb > bk,那么,取走b - bk个物体,即变为奇异局势;如果 a = ak b < bk ,则同时从两堆中拿走 ak - ab - ak个物体,变为奇异局势( ab - ak , ab - ak+ b - ak)(网上发表文章,没有类似word中的公式编辑器,极容易产生误解,为此我暂时规定用<>括起来表示下标,此处应修正为拿走a<k>-a<b-a<k>>,它表示的是 。这个值是怎么来的呢?显然这种情况下我们只能把a,b减去一个相同的值变为奇异局势,我们设为c.并假设a-c=a<m>,b-c=b<m>,b<m>=a<m>+m,联立三个式子得到m=b-a<k>,于是c=a- a<b-a<k>>= a<k>-a<b-a<k>>);如果a > ak b= ak + k,则从第一堆中拿走多余的数量a - ak即可;如果a < akb= ak + k,分两种情况,第一种,a=aj j < k,从第二堆里面拿走 b - bj即可;第二种,a=bj j < k,从第二堆里面拿走 b - aj即可。

    从如上性质可知,两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。

    那么任给一个局势(ab),怎样判断它是不是奇异局势呢?我们有如下公式:

    ak =[k1+5/2]bk= ak + kk=012...,n方括号表示取整函数)(这儿的通项公式本人无法解释,一看无理数就……有时间在网上找一下证明方法。)

奇妙的是其中出现了黄金分割数(1+5/2 = 1618...,因此,akbk组成的矩形近似为黄金矩形,由于2/1+5=(√5-1/2,可以先求出j=[a(√5-1/2],若a=[j1+5/2],那么a = ajbj = aj + j,若不等于,那么如果

  1.[j+1)(√5-1/2]=a并且a+j+1 = b,那么就是奇异局势。

  2.[j-1)(√5-1/2]=a并且a+j-1 = b,那么就是奇异局势。若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。

 

(三)尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

    这种情况最有意思,它与二进制有密切关系,我们用(abc)表示某种局势,首先(000)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是(0nn),只要与对手拿走一样多的物品,最后都将导致(000)。仔细分析一下,(123)也是奇异局势,无论对手如何拿,接下来都可以变为(0nn)的情形。

    计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(123)的按位模2加的结果:

1 =二进制01

2 =二进制10

3 =二进制11+

———————

0 =二进制00(注意不进位)

    对于奇异局势(0nn)也一样,结果也是0

    任何奇异局势(abc)都有a+b+c =0

如果我们面对的是一个非奇异局势(abc),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c变为 a+b,即可,因为有如下的运算结果: a+b+(a+b)=(a+a)+(b+b)=0+0=0。要将c变为a+b,只要从 c中减去 c-a+b)即可。<不够严密吧!漏洞在于可能c<(a+b)>

 

上面的算法准确的应该表示如下:三个数字均表示为二进制时,如果其中某一个数字(设为a)的位数多于另外两个数字各自的位数,按异或运算所得的b+c位数同样小于a,从而其值小于a。因而上述算法可以成立。(*

    1。(142139),14+21=2739-27=12,所以从39中拿走12个物体即可达到奇异局势(142127)。   2。(5581121),55+81=102121-102=19,所以从121中拿走19个物品就形成了奇异局势(5581102)。

    3。(294558),29+45=4858-48=10,从58中拿走10个,变为(294548)。

4。我们来实际进行一盘比赛看看:

         :(7,8,9)->(1,8,9)奇异局势

        :(1,8,9)->(1,8,4)

        :(1,8,4)->(1,5,4)奇异局势

        :(1,5,4)->(1,4,4)

        :(1,4,4)->(0,4,4)奇异局势

        :(0,4,4)->(0,4,2)

        :(0,4,2)->(0,2,2)奇异局势

        :(0,2,2)->(0,2,1)

        :(0,2,1)->(0,1,1)奇异局势

        :(0,1,1)->(0,1,0)

        :(0,1,0)->(0,0,0)奇异局势

        甲胜

作为读者,可能会产生一下几个问题:(1)怎样理解这个问题和二进制的相关性(2)如何证明任意三个数字构成的非奇异局势都可以减小其中之一使其变为奇异局势,如何提供系统的算法?(3)如果减小其中之一可以达到目标,是否减小另外一个就不能达到目标?也就是说算法是否具有唯一性呢?我思考后给出了下面的解答

1)的解答:问题的核心在于证明非(000)的奇异局势不能通过只改变其中的一个数字变为零,这是显然的,因为非(000)的奇异局势中至少有两个数字非零。而一次能且只能改变其中的一个值。

2)的解答:我们可以用递归的方法证明如何证明任意三个数字构成的非奇异局势都可以改变其中之一使其变为奇异局势,并且证明的过程中在一定程度上提供了算法。三个数字均用二进制表示,把三个数字的二进制的位数的最大值记为n,我们对n进行归纳。(1)n1时,非奇异局势只能为(001)或(111)型,显然结论成立。(2)假设n=k时结论成立,当n=k+1时,若去掉k+1位得到的数值为(d,e,f),若(d,e,f)为非奇异局势,姑且设可以减少d使其变为奇异局势。(abck+1位可能的异或和为零,则对(abc)按照(d,e,f)变成奇异局势的算法适当的减小a即可。否则k+1位可能的异或和为1,因此a,b,ck+1位可能为三个1或一个1.若为三个1,只需在(abc)按照(d,e,f)变成奇异局势的基础上在把ak=1位变为0即可。否则为一个1。可能是ak+1位为零,算法亦然:只需在(abc)按照(d,e,f)变成奇异局势的基础上在把ak=1位变为0即可。否则是b或者ck+1位为零,按(*)处的算法即可。

3)的解答:唯一性是不成立的,为此我们只需举出一个反例即可。最简单的反例大概是(331)为非奇异局势,而可以只减少其中一个数字变为(330)或(321),而两者均为奇异局势。其实算法不唯一的非奇异局势应该具有一定的特征,有兴趣的话可以多举几个反例体会一下,然后总结并证明,在此不做讨论。另外这个游戏应该可以由三个数字扩展到任意多个数字。但道理都是一样的。

 

    事实上这种游戏完全可以有千万种变化,而解决类似的游戏的方法在于寻找所谓的奇异局势。我们可以用穷举的方法找出一定数量的数值相对比较小的奇异局势,然后分析并总结出其中的规律。再通过比较系统的证明来确定规律的正确性从而获得普遍的规律。另一方面,即便文中将此谓之为游戏,但事实上大概除了第一个别的并不太可能成为游戏,因为即便明白了其中的规律,在游戏的过程中想要轻易的计算出某个奇异局势也绝非易事。最多也就是数学人的游戏罢了。

#include <stdio.h>#include <math.h>int main(){    int a,b,k,temp,data;    double r=0.6180339887,R=1/r;    while(scanf("%d %d",&a,&b)==2)    {        if(a>b){            temp=b;            b=a;            a=temp;        }        k =b-a;        data=(int)(k*R);        if(a==data)            printf("%d\n",0);        else            printf("%d\n",1);    }    return 0;} 

原创粉丝点击