zoukankan      html  css  js  c++  java
  • 【POJ1067】取石子游戏 (威佐夫博弈)

    【题目】

    Description

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

    Input

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

    Output

    输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。

    Sample Input

    2 1
    8 4
    4 7

    Sample Output

    0
    1
    0

    【分析】

      

      如果甲面对(00),那么甲已经输了,这种局势我们称为平衡状态。前几个平衡状态是:(00)、(12)、(35)、(47)、(610.可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,bk=ak+k

      那么任给一个状态(ab),怎样判断它是不是平衡状态呢?

      我们有如下公式:ak =[k1+5/2]bk= ak + k  k=012...,n 方括号表示取整函数)(奇妙的是其中出现了黄金分割数(1+5/2 = 1.618 ...

      这就是可爱的以及大名鼎鼎的威佐夫博弈。

      

      话说这是为什么呢?怎样证明这个可爱的东西?

      然后我度娘了一下:

      


    方法一

      简单分析一下,容易知道两堆石头地位是一样的,我们用余下的石子数(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个必败态分别为(ak,ak+k),下证:第k+1个必败态为(ak+1,ak+1+k+1)
    从该第k+1个必败态出发,一共可能走向三类状态,从左边堆拿走一些,从右边堆拿走一些,或者从两堆中拿走一些.下面证明这三类都是胜态.
     
    情况一:由命题一,任意一个比a[k+1]小的数都在之前的必败态中出现过,一旦把左边堆拿少了,我们只要再拿成那个数相应的必败态即可。
    情况二(从右边堆拿走不太多):这使得两堆之间的差变小了,比如拿成了(ak+1,ak+1+m),则可再拿成(am,am+m);
    情况二(从右边堆拿走很多):使得右边一堆比左边一堆更少,这时类似于情况一,比如拿成了(ak+1,am)(其中a[m]<a[k+1]) ,则可再拿成(am+m,am);
    情况三:比如拿成(am,am+k+1),则可再拿成(am,am+m).
      综上所述,任何从(ak+1,ak+1+k+1)出发走向的状态都可以走回核中.故原命题成立.
      以上两个命题对于确定(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序列。
      an=[αn],bn=[βn],有 an+n=[(α+1)n]=[βn],解方程 1/(α+1)+1/α=1
      得 α=(sqrt5-1)/2,到此,我们找到了该必败态的通项公式。
      实际上这组Beatty序列还有一些别的性质,比如当一个数是Fibonacci数的时候,另一个数也是Fibonacci数;而且两者的比值也越来越接近黄金比,这些性质在得到通项公式之后不难证明。
      总的来说,这个问题给我们了哪些启示呢?首先用定理所说的方法找核,然后给出核的规律(递推,或是通项)并且证明。
     
    方法二
    定理 0:一个状态是必败态,当且仅当它的所有后继状态都是必胜态;而一个状态是必胜态,只要它的后继状态有一个以上的必败态即可。
    证明略去。
    容易发现下面的定理:
     
    定理 1:(a,b) 和 (b, a) 的胜负性是相同的(a <> b)。
    证明:如果 (a, b) 是必胜态,那么将必胜策略中所有的操作,对第一堆的变为第二堆,对第二堆的变为第一堆,就构成 (b, a) 的必胜策略
     
    定理 2:若 (a, b) 是必败态,则对于所有的 x <> a 和 y <> b,(x, b) 和 (a, y) 是必胜态。
    证明:
    对于 x > a 和 y > b,不管是哪一种情况,总可以从 x 堆或 y 堆中取出一定量的石子使当前状态变为必败态 (a, b),由定理 1,(x, b) 和 (a, y) 为必胜态。
    对于 x < a 和 y < b,不管是哪一种情况,如果 (x, b) 或 (a, y) 是必败态的话,由上述可得 (a, b) 是必胜态,矛盾。故 (x, b) 和 (a, y) 均为为必胜态。
     
    定理 3: 若 (a, b) 是必败态,则对于所有的 d > 0,(a + d, b + d) 是必胜态。
    证明:
    与定理 2 类似。
     
    定理 4:在所有的必败态中,每个数字恰巧出现一次。
    证明:
    有了定理 1,对于对称的状态我们只需要处理其中一个,而两个数不会相同(相同的状态必然是必胜态),于是我们把每个状态中较小的数字放在前面,每行写一个状态,去掉括号并按照升序排列每行的第一个数,就构成了如下的矩阵:
    1 2
    3 5
    4 7
    6 10
    ……
      假设数字k在矩阵中出现两次或两次以上,则有(k,a),(k,b)都为必败态,与定理2矛盾。
      假设数字k为序列中没有出现且值最小的数字,则有 (k,k+i)为必胜态(i>0),则对任意i,必然存在j(0<j<k)使得(k-j,k+i-j)或(k,k+i-j)或(k-j,k+i)为必败态 (若不如此,则无论如何取石子,对方必胜),根据假设,显然(k,k+i-j)必胜,因此,对任意i,必有(k-j,k+i-j)或(k-j,k+i)=0, (0<j<k) 必败
      根据鸽巢原理,必然存在3个i的取值(其实是无穷多个,j只有k-1种取值,而i有无数种)记为i1, i2, i3使得j1=j2=j3=m。对这3个i,同样必然存在一对i,不妨为(i1,i2),使(k-m,k+i1-m)且(k-m,k+i2-m)必败或f(k-m,k+i1)且f(k-m,k+i2)必败。显然与定理2矛盾,因此不存在这样的数k。
      观察这个矩阵,我们又可以得到新的定理:
     
    定理 5:矩阵中每行第一个数恰巧是前面每一行中没有出现过的最小正整数。
    证明:
    由定理 4,矩阵中每个数字恰巧出现一次,而按照这个矩阵的定义,第二列的数总比同行第一列大,第一列又按照升序排列,所以每一行的第一个数正好为前面每一行中没有出现过的最小正整数。
     
    定理 6:矩阵第 i 行的第二个数正好为第一个数加上 i
    证明:
    用数学归纳法。
    1) 对于第一行显然成立
    2) 若对于前 i - 1 行均成立,则所有的 (a[p], a[p] + p) (a[p] 为第 p 行第一个数,p < i) 均为必败态,那么考察第 i 行的状态 (a[i], a[i] + delta)。容易看出 delta >= i,因为如果 delta < i,一定可以通过一次操作变为前面出现过的必败态,那么这个状态就是必胜态。下面由 delta >= i,我们来说明 delta = i。
    首先,我们考虑从第一堆中取出 p 个石子,得到状态 (a[i] - p, a[i] - p + delta),由定理 5,比 a[i] 小的数都在之前出现过,若 a[i] - p 出现在某一行的第一列,由于存在必败态 (a[i] - p, a[i] - p + d) (d < delta),故 (a[i] - p, a[i] - p + delta) 一定为必胜态(定理 2);若 a[i] - p 出现在某一行的第二列,由于第一列是单增的,因而其对应的第一列数必小于 a[i] + delta,故而也可推出其状态为必胜态。
    对于从两堆石子中取出相同数目的情况与之类似,容易看出一定为必胜态。
    于是,(a[i], a[i] + delta) 状态的胜负性只与状态 (a[i], a[i] + d) (d < delta) 有关。不难看出,delta = i 时恰为必败态,因为不论从第二堆中取出多少个石子,作为另一堆的第一堆石子并没有在之前出现过,所以得到的一定是一个必胜态,因而 (a[i], a[i] + delta) 为必败态,由定理 2 及定理 4 可得,原命题成立。即矩阵中第 i 行第二列的数等于同行第一列的数加上 i。
    这时,我们所有的问题都转化到了矩阵上,只要能通过合适的方法表示出这个矩阵,我们就可以很好地解决原问题。
    下面的过程可能需要比较高的数学技巧,首先给出我们需要的一个重要定理([x] 表示 x 的整数部分,{x} 表示 x 的小数部分,即 {x} = x - [x]):
     
    定理 7(Betty 定理):如果存在正无理数 A, B 满足 1/A + 1/B = 1,那么集合 P = { [At], t
    证明:详见Betty定理。
    考虑到 Betty 定理中“恰为 Z
    于是我们得到每一行第二列的数为 [
    我们的目的是要让 Z
    于是应用 Betty 定理,我们得到最终我们需要的定理:
     
    定理 8:上述矩阵中每一行第一列的数为 [
    证明:由 Betty 定理显然得证。
    设a、b是正无理数且 1/a +1/b =1。记P={ 【na】 | n为任意的正整数},Q={ 【nb】 | n 为任意的正整数},则P与Q是Z+的一个划分,即P∩Q为空集且P∪Q为正整数集合Z+。
    证明:因为a、b为正且1/a +1/b=1,则a、b>1,所以对于不同的整数n,【na】各不相同,类似对b有相同的结果。因此任一个整数至多在集合P或Q中出现一次。
    * 现证明P∩Q为空集;(反证法)假设k为P∩Q的一个整数,则存在正整数m、n使得【ma】=【nb】=k。即k < ma、nb<k+1,等价地改写不等式为
    * m/(k+1)< 1/a < m/k及n/(k+1)< 1/b < n/k。相加起来得 (m+n)/(k+1) < 1 < (m+n)/k,即 k < m+n < k+1。这与m、n为整数有矛盾,所以P∩Q为空集。现证明Z+=P∪Q;已知P∪Q是Z+的子集,剩下来只要证明Z+是P∪Q的子集。(反证法)假设Z+(P∪Q)有一个元素k,则存在正整数m、n使得【ma】< k <【(m+1)a】、【nb】< k <【(n+1)b】。 由此得ma < k ≦【 (m+1)a】-1<(m+1)a -1,类似地有nb < k ≦【 (n+1)b】-1<(n+1)b -1。等价地改写为 m/k < 1/a < (m+1)/(k+1)及n/k < 1/b < (n+1)/(k+1)。两式加起来,得
    (m+n)/k < 1 < (m+n+2)/(k+1),即m+n < k < k+1 < m+n+2。这与m, n, k皆为正整数矛盾。所以Z+=P∪Q。

      其实并没有完全懂,只是懂了一点点而已,看看我可爱的图:
     

    结论:

      两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。
      那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:
      ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,...n 方括号表示取整函数)
      奇妙的是其中出现了黄金分割数(1+√5)/2 = 1.618...因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=    [j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,b = aj + j + 1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。
     
      于是,还是找规律大法好,嗯。。黄金比好像很厉害。嗯。。
      所以判断一下(b-a)*(1+√5)/2 是否等于a即可。
     
    代码如下:
     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 
     9 const double q=(1+sqrt(5.0))/2.0;
    10 
    11 int main()
    12 {
    13     int a,b;
    14     while(scanf("%d%d",&a,&b)!=EOF)
    15     {
    16         int t;
    17         if(a>b) t=a,a=b,b=t;
    18         if(((int)((b-a)*q))==a) printf("0
    ");
    19         else printf("1
    ");
    20     }
    21     return 0;
    22 }
    [POJ1067]

    2016-04-21 17:07:41

  • 相关阅读:
    SQLServer中重建聚集索引之后会影响到非聚集索引的索引碎片吗
    设计表的时候,对于自增列做物理主键使用的一点思考
    MySQL慢查询日志相关的配置和使用。
    Python文件操作---合并文本文件内容
    浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题
    从一个简单的约束看规范性的SQL脚本对数据库运维的影响
    (译)内存沉思:多个名称相关的神秘的SQL Server内存消耗者。
    初试Python语法小试牛刀之冒泡排序
    浅析MySQL中的Index Condition Pushdown (ICP 索引条件下推)和Multi-Range Read(MRR 索引多范围查找)查询优化
    MySQL执行计划extra中的using index 和 using where using index 的区别
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5417728.html
Copyright © 2011-2022 走看看