HDU1527——取石子游戏(威佐夫博弈)

来源:互联网 发布:telnet指定端口 编辑:程序博客网 时间:2024/05/29 10:11

题目链接

       这道题是威佐夫博弈的一道入门题,问的十分简单,就是套威佐夫博弈的两个公式即可,因此顺带说说威佐夫博弈,威佐夫博弈和巴什博奕的场景很类似,所以索性就套用我在巴什博奕那篇文章中所描述的的那个场景。有两个二货,比赛拿XX(XX可以是任何东西,只要能定量拿走就好),只是这一次他们不再将XX混为一堆,而是作为两堆(两堆XX的数量均任意个),然后拿走的方式也改为:  1,从一堆里拿,可以拿任意数量个。2,从两堆里分别拿相等数量个。这两种方式二选一,但至少拿走一个XX,若谁取走最后一个XX,谁就赢了。是不是场景变得比巴什博奕麻烦了那么一丢丢啊~~~~

       那么问题来了,如何取胜呢,,,(以下论述均是我参考了百度百科上的论述所写的,如果大家觉得写的太难看,可以直接参照百度百科上的:威佐夫博弈)

       首先,我们标记一下这两堆石头:(a,b),其中a表示当前状态第一堆的数量,b表示当前状态第二堆的数量,(这里我要强调一点:就是这两堆XX它们的价值是等价的,它们是可以互换的,并不一定说第二堆的数量一定比第一堆多,这一点在后续论述中是有一定作用的)

       然后百科上对于(a,b)也给了一个特定的名称叫做“局势”,然后给出一些明显的必败状态(也就是当你面对这些状态时,只要你的对手够聪明,不犯错,无论你怎么拿,你都是必输的)(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)、...... 、(ak,bk) (k = 0, 1, 2, 3,......)。并称这些必败状态为“奇异局势”(至于为什么要叫奇异局势......额......不太清楚,忽略吧~)接下来的工作就是找出这些奇异局势的特点并总结规律。


       然后就会得到a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k。然后公式化就得到了奇异局势的状态公式:

                                  ak = [ k * (1 + √5) / 2 ]     ,   ([x]表示对x取整,也就是 (int)x )

                                  bk = ak + k


       按百科上所说,奇异局势有三个性质——


                                性质1:每个自然数都包含在且只包含在一个奇异局势中。

                                证明:因为ak为在其之前的奇异局势中未出现过的最小的自然数,所以ak的取值一直是保证在之前状态未出现过的数中的最小值,所以每一个当前状态的ak都要比之前的状态的ak要大,即ak>ak-1(k-1是下标),还想不通。。。不要紧,,把k和k-1带入上面ak的公式,这总能接受吧~~~~但ak不一定比bk-1大,看上面给出的几组奇异局势就不难看出。又bk=ak+k>ak-1+(k-1)=bk-1,所以对于任意的奇异状态(ak,bk)之前的状态中一定未出现过其中的数字,但ak取值是自动取当前未出现过的最小的数字,所以每一个自然数都一定会出现,故性质得证。

                           

                                 性质2:对任意的奇异局势,任何合法的操作都会使其成为非奇异局势,也就是奇异局势的所有后继状态均为非奇异局势。

                                 证明:①若只从一堆里取XX,那么另一堆得数量没变,由性质1知,这个没变的自然数只会出现在当前的奇异局势中,所以当另一堆发生变化时,改变后得到的状态一定是非奇异局势。

                                            ②若从两堆里取相同数量的XX,那么由于 bk - ak = k (由公式得),所以他们之间的差值是不会变的,又因为对于任意的奇异局势它的两堆之间的差值是唯一值k,所以这种取法后的状态仍旧是非奇异局势。故性质得证。


                                 性质3:任何非奇异局势都可以通过某种合法操作得到奇异局势,即奇异局势的所有后继状态中存在奇异局势。

                                 证明:对于任意的一个非奇异局势(x,y),由性质1知:任何自然数均会出现在一个奇异局势中,所以要么 x = ak,要么 y = b(k ∈ { 0, 1, 2, 3, 4, 5, .......}),所以分类讨论:

                                            ①若x = ak,y > bk,那么y减去(y - bk)即可得到奇异局势(ak , bk).

                                            ②若x = ak,y < bk,那么两堆同时减掉x-a(y-x)  (y-x为下标),得到奇异局势(a(y-x) , a(y-x)+y-x).

                                            ③若x > ak,y = bk,那么x减去(x - ak)即可得到奇异局势(ak , bk).

                                            ④若x < ak,y = bk,这时又要对该状况细化分类讨论:

                                                                情况(1): x = aj , (j < k),此时从y中拿走(y - bj)即可得到奇异局势(aj , bj),

                                                                情况(2): x = bj , (j < k),此时从y中拿走(y - aj)即可得到奇异局势(aj , bj).

                                             这里的④为什么要分类呢?这就要注意上文中我曾提到的强调点,这两堆是等价值的,也就是情况(2)得到奇异局势其实是(bj , aj),此时第一堆是比第二堆多的,为了同意奇异局势的格式才把它写成(aj , bj)。所以细化分类讨论的其实是对操作后  第一堆多余第二堆 和 第二堆多余第一堆 的两种情况进行讨论。这样性质3也得证。

        好了,解释了这么多,回到此题正解,这道题就是套上述的ak和bk的公式,若符合奇异局势,则先手输,否则先手胜,输出对应结果即可。


#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<algorithm>using namespace std;int main(){    //freopen("in.in","r",stdin);    //freopen("out.out","w",stdout);    int n, m;    while(scanf("%d%d",&n,&m)!=EOF)    {        int a=min(n,m);        int b=max(n,m);        double k=(double)b-a;        int term=(int)(k*(1+sqrt(5))/2);        if(term==a)            printf("0\n");        else            printf("1\n");    }    return 0;}


0 0