C

来源:互联网 发布:linux pyqt4安装 编辑:程序博客网 时间:2024/06/05 00:12
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。
Output
输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。
Sample Input
2 18 44 7
Sample Output
01

0

题目分析:

首先我们根据条件来分析博弈中的奇异局势

    第一个(0 , 0),先手输,当游戏某一方面对( 0 , 0)时,他没有办法取了,那么肯定是先手在上一局取完了,那么输。

第二个 ( 1  , 2  ),先手输,先手只有四种取法,

1)取 1 中的一个,那么后手取第二堆中两个。

2)取 2 中一个,那么后手在两堆中各取一个。

3)在 2 中取两个,那么后手在第一堆中取一个。

4)两堆中各取一个,那么后手在第二堆中取一个。

可以看出,不论先手怎么取,后说总是能赢。所以先手必输!

第三个 ( 3 , 5 ),先手必输。首先先手必定不能把任意一堆取完,如果取完了很明显后手取完另一堆先手必输,那么

假如看取一堆的情况,假设先手先在第一堆中取。 取 1 个,后手第二堆中取4个,变成(1 ,2)了,上面分析了是先手的必输局。

 取 2 个,后手第二堆中取3个,也变成( 1 , 2)局面了。

假设先手在第二堆中取,取 1 个,那么后手在两堆中各取 2 个,也变成 ( 1 , 2 )局面了。

   取 2 个 ,那么后手可以两堆中都去三个, 变成 ( 0 , 0)局面,上面分析其必输。

   取  3  个,后手两堆各取 1 个 ,变成( 1 , 2)局面了。

  取 4 个,后手在第一堆中取一个,变成( 1 , 2)局面了。

可见不论先手怎么取,其必输!

第四个(4  , 7),先手必输。

自己推理可以发现不论第一次先手如何取,那么后手总是会变成前面分析过的先手的必输局面。

那么到底有什么规律没有呢,我们继续往下写。

第四个 ( 6 ,10  )

第五个 ( 8 ,13)

第六个 ( 9 , 15)

第七个 ( 11 ,18)

会发现他们的差值是递增的,为 0 , 1 , 2, 3, 4 , 5 , 6, 7.....n

而用数学方法分析发现局面中第一个值为前面局面中没有出现过的第一个值,比如第三个局面,前面出现了 0  1 2,那么第三个局面的第一个值为 3 ,比如第五个局面,前

面出现了 0  1  2 3 4 5 ,那么第五个局面第一个值为6。

再找规律的话我们会发现,第一个值 = 差值 * 1.618 

而1.618 = (sqrt(5)+ 1) /  2 。

大家都知道0.618是黄金分割率

而威佐夫博弈正好是1.618,这就是博弈的奇妙之处!

方法:首先求出差值,差值 * 1.618 (写为(sqrt(5)+ 1) /  2 比较好)== 最小值 的话先手输,否则先手赢。

C代码:

#include <stdio.h>#include <stdlib.h>#include <math.h>int main(){    int m,n;    while(~scanf("%d%d",&m,&n))    {    if(m>n)//前者大于后者,交换两者,让m总是为最小的那个    {        int t;        t=m;        m=n;        n=t;    }    int q=floor((n-m)*(sqrt(5.0)+1)/2.0);    if(q==m)    printf("0\n");//先手输    else        printf("1\n");//先手赢    }    return 0;}

C++代码:

#include <cstdio>#include <cmath>#include <iostream>using namespace std;int main(){    int n1,n2,temp;    while(cin>>n1>>n2)    {        if(n1>n2)            swap(n1,n2);        temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);//向下取整,与“四舍五入”不同,        //向下取整是直接取按照数轴上最接近要求值的左边值,即不大于要求值的最大的那个值        if(temp==n1)            cout<<"0"<<endl;        else            cout<<"1"<<endl;    }    return 0;}
奇异局势有如下三条性质:

    1。任何自然数都包含在一个且仅有一个奇异局势中。
    由于ak是未在前面出现过的最小自然数,所以有ak > ak-1 ,而 bk= ak + k > ak-1 + k-1 = bk-1 > ak-1 。所以性质1。成立。
    2。任意操作都可将奇异局势变为非奇异局势。
    事实上,若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。如果使(ak,bk)的两个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。
    3。采用适当的方法,可以将非奇异局势变为奇异局势。

    假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(0,0);如果a = ak ,b > bk,那么,取走b  - bk个物体,即变为奇异局势;如果 a = ak ,  b < bk ,则同时从两堆中拿走 ak - ab - ak个物体,变为奇异局势( ab - ak , ab - ak+ b - ak);如果a > ak ,b= ak + k,则从第一堆中拿走多余的数量a - ak 即可;如果a < ak ,b= ak + k,分两种情况,第一种,a=aj (j < k),从第二堆里面拿走 b - bj 即可;第二种,a=bj (j < k),从第二堆里面拿走 b - aj 即可。

    从如上性质可知,两个人如果都采用正确操作,那么面对奇异局势,先拿者必输;非奇异局势,先拿者必胜!
参考文章:博弈之威佐夫博弈详解 http://blog.csdn.net/y990041769/article/details/21694007
          奇异局势 http://blog.csdn.net/u011519618/article/details/13749311

原创粉丝点击