威佐夫博弈详解

部分内容参考:http://blog.csdn.net/lgdblue/article/details/15809893

威佐夫博弈(Wythoff Game)

问题模型:

有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,

规定每次至少取一个,多者不限,最后取光者得胜。


策略:

我们用(ak,bk) (ak<=bk  k=0,1,2,3,....n)表示两堆物品的数量,并称其为局势。


如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势

我们可以这么理解,当面临某个局势则处于必败态的局势称为奇异局势。

前几个奇异局势:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(11,18),(12,20)....

可以看出a0=b0=0.ak是前面未出现过的最小自然数,并且bk=ak+k


奇异局势的特点:

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

 由于ak是前面未出现过的最小自然数,所以有ak>a(k-1).并且bk=ak + k > a(k-1) + k - 1 = b(k-1) > a(k-1).


2、任何操作都可以将奇异局势变成非奇异局势。


 如果只改变奇异局势(ak,bk)的某一个分量,那么由于另一个分量并没有改变,有性质1可知,这一步会将奇异局势变成非奇异局势。如果同时将两个分量减少,则其差不变(都是k).且不可能是其他奇异局势的差,则也是从奇异局势变成非奇异局势。


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

    假设当前局势是非奇异局势(a,b)。

1)如果a=b,则同时从两堆中取走a个,就变成了奇异局势(0,0)。例如(5,5)==>(0,0)


2)如果a=ak,b>bk,则从b堆取走b-bk个,变成奇异局势(ak,bk)。例如(3,7)==>(3,5)


3)如果a>ak,b=bk,则从a堆取走a-ak个,变成奇异局势(ak,bk)。例如(5,7)==>(4,7)


4、如果b>b(b-a)并且a>a(b-a),则同时从两堆中取走a-a(b-a)个,则变成奇异局势(a(b-a),b(b-a))

例如5  8 ,5>a(8-5)=a3=4  8>b(8-5)=b3=7 从两堆中取走a-a(b-a)=5-4=1个,变成奇异局势(4,7)。

例如4 6 ,4>a(6-4)=a2=3  6>b(6-4)=b2=5 从两堆中取走a-a(b-a)=4-3=1个,变成奇异局势(3,5)。

可以理解成变成差为b-a的奇异局势。


5、如果a=bk并且b-a!=k,则从b堆中取走b-ak个,变成奇异局势(ak,bk).

例如,5 10 ,5=b2 10-5=5!=2 则从10中取走10-a2=10-3=7个,变成奇异局势(3,5)。

为什么要b-a!=k呢?例如7 10 , 7=a3,10-7=3=k 也可以变成奇异局势(4,7)。但这已经在4)判断过了。


总结:当开始的局势为奇异局势,则后手必胜。

当开始的局势为奇异局势,则手必胜。

(前提在双方都采取最佳方案)。


如何判断是否为奇异局势

先确定奇异局势的通项公式:

   ak=,向下取整。 bk=ak+k。

那么由于bk-ak=k,则判断ak是否与(bk-ak)*相等。

相等即可判断是为奇异局势。


证明奇异局势的通项公式:

辅助定理:

贝亚蒂定理(Beatty Sequence)

,使得定义集(贝亚蒂列

和 构成正整数集的一个分划:


即是说:若两个正无理数倒数之和是1,则任何正整数都可刚好以一种形式表示为

不大于其中一个无理数正整数倍的最大整数。


在威佐夫博弈中,p=,q=.

1/p+1/q=1/+1/

=+

=/

=/=1.

证明完毕。

即是a为P集合的数,b为Q集合的数。


威佐夫博弈(裸题) hdu 1527 代码:

 

/*/////////////////////////////
HDU 1527 
题意:
有两堆石子。由两个人轮流取石子。有两种不同的取法,一是可以在任意
的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。
最后把石子全部取完者为胜者。

分析:
如果当前局势是奇异局势,则后手必胜。
如果当前局势是非奇异局势,则先手必胜。

/////////////////////////////*/
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;

int main()
{
    int a,b;
    while(scanf("%d %d",&a,&b)!=EOF)
    {
        if(a>b) swap(a,b);      //使得a小于b
        int temp=floor((b-a)*(1+sqrt(5.0))/2.0);
        if(temp==a)
            printf("0\n");
        else 
            printf("1\n");
    }
}


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013075699/article/details/43024381
个人分类: 算法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭