zoukankan      html  css  js  c++  java
  • 博弈论3

    威佐夫问题

    转自http://yjq24.blogbus.com/logs/42826226.html 

    大致上是这样的:有两堆石子,不妨先认为一堆有10,另一堆有15个,双方轮流取走一些石子,合法的取法有如下两种:

    1)在一堆石子中取走任意多颗;

    2)在两堆石子中取走相同多的任意颗;

    约定取走最后一颗石子的人为赢家,求必败态(必胜策略)。

    这个可以说是MR.Wythoff(Wythoff于1907年提出此游戏)一生全部的贡献吧,我在一篇日志里就说完有点残酷。这个问题好像被用作编程竞赛的题目,网上有很多把它Label为POJ1067,不过如果学编程的人不知道Beatty定理和Beatty序列 ,他们所做的只能是找规律而已。不熟悉的人可以先在这里 玩几局~

    简单分析一下,容易知道两堆石头地位是一样的,我们用余下的石子数(a,b)来表示状态,并画在平面直角坐标系上。

    用之前的定理: 有限个结点的无回路有向图有唯一的核  中所述的方法寻找必败态。先标出(0,0),然后划去所有(0,k),(k,0),(k,k)的格点;然后找y=x上方未被划去的格点,标出(1,2),然后划去(1,k),(k,2),(1+k,2+k),同时标出对称点(2,1),划去(2,k),(1,k),(2+k,1+k);然后在未被划去的点中在y=x上方再找出(3,5)。。。按照这样的方法做下去,如果只列出a<=b的必败态的话,前面的一些是(0,0),(1,2),(3,5),(4,7),(6,10),…

    接下来就是找规律的过程了,忽略(0,0),记第n组必败态为(a[n],b[n])

    命题一:a[n+1]=前n组必败态中未出现过的最小正整数

    [分析]:如果a[n+1]不是未出现的数中最小的,那么可以从a[n+1]的状态走到一个使a[n+1]更小的状态,和我们的寻找方法矛盾。

    命题二:b[n]=a[n]+n

    [分析]:归纳法:若前k个必败态分别为 ,下证:第k+1个必败态为

    从该第k+1个必败态出发,一共可能走向三类状态,从左边堆拿走一些,从右边堆拿走一些,或者从两堆中拿走一些.下面证明这三类都是胜态.

    情况一:由命题一,任意一个比a[k+1]小的数都在之前的必败态中出现过,一旦把左边堆拿少了,我们只要再拿成那个数相应的必败态即可。

    情况二(从右边堆拿走不太多):这使得两堆之间的差变小了,比如拿成了 ,则可再拿成

    情况二(从右边堆拿走很多):使得右边一堆比左边一堆更少,这时类似于情况一,比如拿成了 (其中a[m] ;

    情况三:比如拿成 ,则可再拿成

    综上所述,任何从 出发走向的状态都可以走回核中.故原命题成立.

    以上两个命题对于确定(a[n],b[n])是完备的了,给定(0,0)然后按照这两个命题,就可以写出(1,2),(3,5),(4,7),…

    这样我们得到了这个数列的递推式,以下我们把这两个命题当成是(a[n],b[n])的定义。

    先证明两个性质:

    性质一:核中的a[n],b[n]遍历所有正整数。

    [分析]:由命题一,二可得a[n],b[n]是递增的,且由a[n]的定义显然。

    性质二:A={a[n]:n=1,2,3,…},B={b[n]:n=1,2,3,…},则集合A,B不交。

    [分析]:由核是内固集,显然。

    看到这里大家有没有想到Beatty序列呢,实际上a[n]和b[n]就是一个Beatty序列。

    ,有 ,解方程

    ,到此,我们找到了该必败态的通项公式。

    实际上这组Beatty序列还有一些别的性质,比如当一个数是Fibonacci数的时候,另一个数也是Fibonacci数;而且两者的比值也越来越接近黄金比,这些性质在得到通项公式之后不难证明。

    总的来说,这个问题给我们了哪些启示呢?首先用定理所说的方法找核,然后给出核的规律(递推,或是通项)并且证明。最后附上一张对应的必败态图.

    wythoff

    上次说了胜态和必败态,还记得最后的练习么?桌子上有15个石子,每人每次可以拿去1个或3个石子,拿走最后一个石子的人赢,列出所有的必败态:0,2,4,6,8,10,12,14。说过了状态作为结点可以画一张有向图,下面这张图就是这个游戏所对应的:

    dg1 我只列了不大于6的状态,回顾一下胜态和必败态的性质:
    胜态一定可以通过某种策略走向必败态;而必败态采取任何策略都将走向胜态。
    用图论的话来说, 因为必败态只能走向胜态,所以任何两个必败态结点之间不可能存在边; 因为胜态总能走到必败态,所以对任何一个非必败态的结点,一定存在一个从它指向必败态结点的边。
    不妨看看左图中的0,2,4,6,亲自体会一下。

    定义:有向图中,集合X中任意两点之间无边,称集合X为内固集。 定义:有向图中,任意不在集合X中的点存在一条指向集合X的边,称集合X为外固集。
    定义:有向图中,集合X 既是外固集,又是内固集,称集合X为核。

    显然,内,外固集的定义正好针对上面的两句话,而核就是包含所有必败态的集合。

    定理:双人博弈中,约定走最后一步为胜,如果有核存在,则其中一方有不败策略。
    证明:不妨设A先行动,初始状态不在核中,由于核是外固集,A一定可以采取某种策略把状态走到核中,然后轮到B;由于核是外固集,所以B不管采取什么策略,都将走出核,所以轮到A的时候,A又可以把状态走进核里。总而言之,A可以使B永远面临核内的状态。无路可走的状态不可能在核外,因为核外总能走到核内,A可以保持不败。如果初始状态不在核中,那么利用同样的想法易知B有不败策略。

    以上的定理意义是非凡的,虽然这个定理在证明之前我们其实就已经了解了核与必败态的紧密联系。那么,对一个博弈游戏来说,找出核是核心问题。在此之前,先得考察核得存在性:

    定理:有限个结点的无回路有向图有唯一的核。

    证明:核可以用如下的方式找出:首先找出没有后继结点的点集P[1](最基本的必败态,比如上图中的结点0),然后找到那些指向P[1]的结点集合为N[1](最基本的胜态,比如上图的结点1和结点3);然后,除去P[1]和N[1]中的点并除去和这些点关联的边,继续寻找没有后继结点的点集P[2](更高级的必败态,比如上图中的结点2),依次类推,则最后的核为P=P[1]并P[2]并…并P[n]。

    很容易说明如此找到的核是内固集,也是外固集,满足核的定义,下面说明一下核为什么不是空集:实际上P[1]就不是空集,对一个没有回路的有向图来说,从图上的某一点出发,就无法回到原来到过的点。而图中的点又是有限的,所以最后必将在某个结点终止,故P不是空集。

    针对不同的游戏,找核是一个麻烦事。首先生成图,有向边取决于游戏规则,然后当我们要找某个必败态的时候,是要先找到之前所有的必败态的,而这正是一个数学问题和一个编程问题的关键差别。在立方和分解问题[unsolved]中,我的问题的提法都是针对某一个特定输入的n来看是否存在(x,y)满足立方和或者平方和等于n.实际上,如果提法换成,输出对所有不大于n的数中可以被分解的数,那么这种提法更适合计算机去解决,因为本质上来说,两个问题是不一样的。对于前者我只需要知道有关n的情况就可以了,而对后者,却调动了资源去计算所有不大于n的数的情况。虽然他们看起来很相近,但是从道理上来说应该后者的劳动量要大得多,可悲的事情就在于,有时候你要算出n的情况,就不得不算一些比n小的数的情况,而这个计算的数目通常是随着n增大而增大的;另一个可悲的事情是,程序员往往已经习惯了第二种提问方式。数学家希望找到某些必要条件或者充分条件来确定n能否被分解,同样的道理,我们也希望能直接找到必败态的规律,而不真正依赖于象上述定理那样递归的思想从P[1]开始找起,这样来解决问题。

    但是,必败态的规律是严格依赖于规则的,这一点对找出必败态的规律来说造成了很大的局限性。这个图的模型在以后还会遇到,到时有更好的方法来寻找必败态。

    附件:立方和分解问题

     则称自然数对(x,y)作为n的立方和分解,试求出给定n的所有分解方案.

    在此之前先考虑下平方和分解,这个相对容易些?

     

    下面是一个方案:

    for x:=0 to floor(sqrt(n/2)) do
      for y:= x to n do
         if x*x+y*y=n then 输出(x,y)

    另一个思路是,从图象上去分析,这是一段曲线上的整点问题,当然应该在曲线附近搜索才是,下面的代码尽可能的让搜索的点在圆的内侧边缘

    y:=floor(sqrt(n))
    x:=0
    while x<=y do
      begin
        if x*x+y*y<n then x:=x+1
        else if x*x+y*y=n then
           begin
             输出(n,x,y)
             x:=x+1
             y:=y-1
          end
        else if x*x+y*y>n then y:=y-1
      end

    以上的代码最好结合圆弧来看(程序搜索1/8圆弧),实际上,x也不用一次次+1而可以直接跳到 处,我很喜欢这个算法,因为在图像上这看起来很有意思。

    为什么会要做平方和?因为在无穷下降法 中提到的Fermat平方和定理 已经把问题解决了,由Fermat平方和定理,很容易得到推论:把n分解质因数之后,4k+3型质数的次数是偶次时才可以分解。事实上4k+1型质数的分解也有具体数学方法(连分数法),这里不赘述了,有兴趣的可以查资料。关键是,从这里我们可以把n分解质因数,把质因数分成两类,2和4k+1与4k+3,2和4k+1用之前的搜索来分解,而4k+3出现如果是奇数次,那么这个数本身就不能分解;如果是偶数次,其本身就是一种分解(p^2+0^2),再利用Fermat平方和定理证明的第一步结论:

     

    这个式子本身就很有分治法的感觉,而且由Fermat定理,质数的分解是惟一的

    即可得到需要的结果,当质因子较多时,需考虑每种质因子的组合(这可能是个麻烦点),下面给出两个例子:

    例一:

    分解一:

    分解二:

    分解三: (不同组合的分解可能重复,且分解会破坏原来的x<=y)

    例二:

    平方和分解扯了太多了,把平方和的第二种算法稍作修改就能作为立方和分解的代码了,可是立方和问题上数学能帮上什么忙么?我们没有Niubi立方和定理,质因数分解也不一定也行得通了,但是我们可以类似于上面的“n中含奇数次4k+3型质数则n必不可分解为平方和”这样,找一些立方和分解的必要条件:

     

      //消元,消去y

    //判别式,注意x,y为整数解则必须delta为完全平方数

    //由此可知a,k 奇偶性相同,这是一个充要条件

    这样我们就得到了一个方法,把n分解质因数,考虑质因数的组合得到(a,b),验证充要条件是否成立.

    但是这个似乎对搜索的帮助并不大,如果单纯的用质因子来考虑很可能还不如之前的搜索方案,在做数值分析时,注意到所有的n都有这样的性质 n^3 mod 9 = 0,1,-1,也许这也是一个必要条件,或许可以考虑证明。

    这个问题留待以后解决,下面分享一个相关题:

    存在两组不同的正整数(x,y)时,称n为双倍立方数.

    双倍立方数比起对应平方的平行概念来说稀有许多,最小的双倍平方数是50=1^2+7^2=5^2+5^2

    利用程序我们找到了最小的双倍立方数为1729=1^3+12^3=9^3+10^(最好能记住这个数1729)

    现在的问题是,最小的三倍立方数是多少?

    即满足 有两组不同的正整数解(x,y,z)的最小的n

    根据条件,n<=1730=1^3+1^3+12^3=1^3+9^3+10^3

      //需要搜索的范围不大,1<=x1,y1,z1<=12

    手工构建一张a^3-b^3表:(应该是12X12的,我这里简略了)

    ba 1 2 3 4 5 6
    1   7 26 63 124 215
    2     19 56 117 208
    3       37 98 189
    4         61 152
    5           91
    6            

    仔细看一看里面有没有两个数之和为第三个数的?稍微好一点的方法是从左到右,从下到上求和,考察其和是否出现在表格右上方。

    这样会先找到98+117=215,然后找到91+124=215,显然应该选择第一个,后一个在等式左右都有最大项6^3,其值一定不会小,

    最后,答案就是251=2^3+3^3+6^3=1^3+5^3+5^3

    *****************************************************************

    //再继续看看必败点

    一、
          m(k) = k * (1 + sqrt(5))/2
          n(k) = m(k) + k
     二、
     
    一个必败点有如下性质:
    性质1:所有自然数都会出现在一个必败点中,且仅会出现在一个必败点中;
    性质2:规则允许的任意操作可将必败点移动到必胜点;
    性质3:一定存在规则允许的某种操作可将必胜点移动到必败点;
     
    下面我们证明这3个性质。
     
    性质1:所有自然数都会出现在一个必败点中,且仅会出现在一个必败点中;
    证明:m(k)是前面没有出现过的最小自然数,自然与前k-1个必败点中的数字都不同;m(k)>m(k-1),否则违背m(k-1)的选择原则;n(k)=m(k)+k>m(k-1)+(k-1)=n(k-1)>m(k-1),因此n(k)比以往出现的任何数都大,即也没有出现过。又由于m(k)的选择原则,所有自然数都会出现在某个必败点中。
     
     
    性质2:规则允许的任意操作可将必败点移动到必胜点;
    证明:以必败点(m(k),n(k))为例。若只改变两个数中的一个,由于性质1,则得到的点一定是必胜点;若同时增加两个数,由于不能改变两数之差,又有n(k)-m(k)=k,故得到的点也一定是必胜点。
     
     
    性质3:一定存在规则允许的某种操作可将必胜点移动到必败点;
    证明:以某个必胜点(i,j)为例,其中j>i。因为所有自然数都会出现在某个必败点中,故要么i等于m(k),要么j等于n(k)。
    若i=m(k),j>n(k),可从j中取走j-n(k)个石子到达必败点;
    若i=m(k),j<n(k),可从两堆同时拿走m(k)-m(j-m(k)),注意此时j-m(k) < n(k)-m(k) < k,从而到达必败点( m(j-m(k)),m(j-m(k))+j-m(k));
    若i>m(k),j=n(k),可从i中取走i-m(k)个石子到达必败点;
    若i<m(k),j=n(k),需要再分两种情况,因为i一定也出现在某个必败点中,若i=m(l),则从j中拿走j-n(l),若i=n(l),则从j中拿走j-m(l),从而到达必败点(m(l),n(l))。

     

    //看完上面的有了点了解吧,代码如下:

     1 #include<iostream>
     2 #include<cmath>
     3 using namespace std;
     4 int main ()
     5 {
     6     int a,b,dif;
     7     double p=(sqrt((double)5)+1)/double(2);
     8     while(cin>>a>>b)
     9     {
    10     dif=abs(a-b);//取差值
    11     a=a<b?a:b;//取较小的值
    12     if(a==(int)(p*dif))//判断是不是奇异局势
    13       printf("0
    ");
    14     else printf("1
    ");
    15     }
    16     return 0;
    17 }
  • 相关阅读:
    各种犯下的错误(2)
    c3p0封装
    servlet模板
    各种犯下的错误(1)
    连接池的创建与封装
    jdbc连接用工具类
    Java从入门到入坟(1)
    小米商城网页版(js+css)
    JavaScript学习篇(9)
    JavaScript学习篇(8)
  • 原文地址:https://www.cnblogs.com/xiaojingang/p/3974036.html
Copyright © 2011-2022 走看看