• Games:取石子游戏(POJ 1067)


    取石子游戏
                         
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 37662   Accepted: 12594

    Description

    有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

    Input

    输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

    Output

    输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。                                        
     
     
     
     
     
     
     
     
     
    2015-08-19:
     
      这道题比较有趣,代码量不多,但是里面的数学知识蕴含比较丰富。
    这题就是著名的威佐夫博弈
     
      如题所言,我们要做的就是要确定谁是最后的赢家,那么这题呢,取石子的方法有很多(千万不要被采取最好的策略给骗了,不是一定要取完的意思),我们总不可能一个一个地枚举把,那样太累了,也不可取,那怎么办呢?其实,在双人博弈中,只要是把棋子下完就算获胜的那种,且满足一定规则,那么一定存在有一方一定胜的情况,这个其实是图论的知识,我们等一下再讲,不急。
     
      我们现在先观察一下,既然有一定是赢的情况,那么根据题意,我们最容易想到的就是(0,k),(k,0),(k,k)这三种情况,如果存在这三种情况,我们一定赢,那如果我们一定输的情况长什么样子的呢?我们想想,(1,2),(2,1),(3,5),(5,3)....这类的情况我们一定是输的,不信你可以试试看,我们就拿(1,2)来看,无论你把哪一边的石头取完,或者取一个之类的,你都是输。
     
      这样看,貌似这题真的难透了,因为不仅存在一定赢的情况,而且也存在一定输的情况,还存在不一定赢也不一定输的情况,那完蛋了,这题是不是没法做了呢?别急,我们这样想:
     
      如果你在必胜态上,不用想,你赢了。这种情况的前提是对手在必败态上
      如果你要保证你自己赢,首先你自己就不能在必败态,而且最好你下完以后对手一定在必败态上,这种思路可以,
      如果你不在必胜态上,你可以把自己转移到必胜态上,或者把对手逼到必败态上
     
      这样一想那么这题就好做了,我们只用找必败态就好了,关键是怎么找呢?
      带着这个疑问,我们来讲一下非常重要的模型:博弈的图论模型---必败态与核1
       TH1:胜态一定可以通过某种策略走向必败态;而必败态采取任何策略都将走向胜态。
     
       图论语言:
       TH2:因为必败态只能走向胜态,所以任何两个必败态结点之间不可能存在边;
       TH3:因为胜态总能走到必败态,所以对任何一个非必败态的结点,
          一定存在一个从它指向必败态结点的边。

       定义1:有向图中,集合X中任意两点之间无边,称集合X为内固集。
       定义2:有向图中,任意不在集合X中的点存在一条指向集合X的边,称集合X为外固集。
       定义3:有向图中,集合X 既是外固集,又是内固集,称集合X为核。
     
       TH4:双人博弈中,约定走最后一步为胜,如果有核存在,则其中一方有不败策略。
       TH5:有限个结点的无回路有向图有唯一的核。
      定理1定理2和定理3我们不证(这个根据图来理解比较好一点),
      对于定理4,因为博弈肯定对应的是有向图,我们可以假设A先走,A总是做到会把B逼入核中的情况,然后B可以退出核外(假设还是存在往外指的边),总是存在A最后会把B逼到走投无路的情况(当然你可能会问如果B退出来以后A走投无路怎么办,那不可能,因为如果是这样,A早就在核中了,违反了核的定义)。同理B也是一样分析
      对于定理5:因为图无回路,所以一定是有终点的,终点的集合即是核。
     
     
     
     
      好了知道了图论的这个知识以后,回到题目来,那么这道题,必败态就是核的集合了,那怎么找到核呢?我们可以递推的思想,找一下规律
      我们知道(0,0)是一个特殊的必败点,那么根据非必败点能走到必败点的结论,我们根据题目的条件,我们可以用3条线去掉非必败点,横线,竖线,和斜线,那么我们就去掉了(0,k),(k,0),(k,k)(k>1)的点,
      接下来我们找第一个没有划的点,他一定是一个必败点,因为这个点不可能和(0,0)有交集,符合核的定义,我们找到了(2,1)和(1,2),我们也按照上面的处理方法,划线。
      接下来就是(3,5),(5,3)这两个必败点,同理,然后就是(4,7)(7,4)………………………………一直往后推
     
      现在我们把这些点全部集中起来看,好了发现规律没?规律就是a(k)=b(k)+k,这个东西咱们写代码应该要熟悉,这个式子的a(k)和b(k)的比率,就是黄金分割率0.618(当然k要很大才是趋近这个数)
    是不是有点奇怪?你可能会说,不行啊这只是我们画图推出来的规律,怎么可以拿来做结论呢?好吧,下面我们来稍微证明下:
     
      证明{(a(k),b(k))|a(k)=b(k)+k}均在核中:
    反证法:  
    假设存在一个{(a(k),b(k))|a(k)=b(k)+k}不在核中,那么这个点呢一定会与某一个核存在边,那么边怎么来?要么就是横着过来,竖着过来,或者斜着过来(即存在另一个节点(c(n),d(n)),使得其坐标等于c(n)=a(k)-m或者d(n)=b(k)-m或者c(n)=a(k)-m,d(n)=b(k)-m),这样想肯定不对,因为在考虑(c(n),d(n))之前,我们已经把这些边和边上的节点全部排除了,
    所以,{(a(k),b(k))|a(k)=b(k)+k}均在核中。证毕
     
      另外,这个结论可以引出第二个非常著名的定理:Beatty定理2
     
      Beatty定理是个什么东西,大家可以在下面的参考资料那里看看,
    我们这里只讲结论,就是威佐夫博弈的必败点坐标满足Beatty定理并且如果a(n)=[αn],b(n)=[βn],则α=(sqrt(5)-1)/2;
     
      那么接下来就是给大家看一下威佐夫博弈的代码,真的是简单的要死:
    #include <stdio.h>
    #include <math.h>
    
    int main(void)
    {
        long double p = (sqrt((long double)5) + (long double)1) / (long double)2;
        int a, b, k;
    
        while (~scanf("%d%d",&a,&b))
        {
            k = b > a ? b - a : a - b;
            a = b > a ? a : b;
            if (a == (int)(p*k)) printf("0
    ");
            else printf("1
    ");
        }
    }

    参考资料:

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明

    1.Patrick的博客--取石子游戏

    (我的那个证明方法是反证,他那个是数学归纳法,更严谨一点)

    2.Jack Ge的博客--取石子游戏

    3.败态的过程

    4.如何证明高斯取整函数和Beatty公式

    5.如何证明高斯取整函数和Beatty公式

  • 相关阅读:
    【记录】20060430 11:30:00 本Blog访问量突破100000 !
    ESFramework介绍之(24)―― 日志记录IEsbLogger
    ESFramework介绍之(20)―― 插件自动升级
    ESFramework介绍之(21)-- Tcp组件接口ITcp介绍
    ESFramework介绍之(17)―― 支持漫游用户和跨区域功能请求
    python标准库学习9
    python标准库学习5 bisect — Array bisection algorithm
    C++中四种显示类型转换总结
    BeautifulSoup学习笔记
    jdbc连接数据库(水文)
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4742415.html
Copyright © 2020-2023  润新知