取石子问题--威佐夫博弈(Wythoff‘s game)

题目描述

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

对于一开始自己的想法是采用递归,后面发现不符合,然后自己慢慢去找必输的组合数

  第一个(0,0),肯定是先手输,为啥?因为当先手兴冲冲地上来准备拿第一手时,发现已经是(0,0)了,他没石子可拿了,那最后的石子去哪了?肯定在上一局被它对手取光了,所以先手只能认输,而对手稳赢,因为规则就是第一个把石头取光的赢得胜利。

    第二个(1,2),也是先手必输,为啥?因为先手上来取第一手时他只有四种取法:

        1):在1中取1个,那么后手就把2中剩余的2个全部取光:先手输,后手赢

        2):在2中取1个,那么后手在两堆中各取1个,石头又光了,先手又输了

        3):在2中取两个,后手取1中剩下的一个,石头又光了,先手又输了

        4):两堆中各取1个,后手取走2中剩余的1个,石头又光了,先手又输了

    综上所述,对于(1,2)这种情况,无论先手怎么取,都是死路一条,必输!

    第三个(3,5),先手还是死路一条,无论先手怎么取,最后兜兜转转都回到情形(1,2),上面已经分析过了,(1,2)先手必死无疑,可怜的先手啊!

    第四个 ( 6 ,10  )

    第五个 ( 8 ,13)

    第六个 ( 9 , 15)

    第七个 ( 11 ,18)……这些情况先手毫无招架能力,只能认输,那么这些数字到底有什么规律?规律有两个:
    一是从(0,0)开始到(11,18),两个数之间的差值是递增的分别是0,1,2,3,4,5,6,7……

    二是每一局中的第一个值是前面所有的局中没有出现的数字,比如第三个局面,前面出现了 0  1 2,那么第三个局面的第一个值为 3 ,比如第五个局面,前

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

对于博弈论自己也不是很了解,就在百度上查找了威佐夫博弈

其实最后的总结就是:两堆石子的差值的1.618倍是否等于较小的那一个

第一个值 = 差值*1.618,这个才是解决此题的关键,而1.618 = (sqrt(5)+ 1) /  2 ,所以当我们拿着任意一组的两个值,只要判断一下是否符合“ 第一个值 = 差值*1.618”即可,如果是,那就是先手必输,不是,先手必赢!

#include
 int main() {
    int a = 0, b = 0;
    while (~scanf("%d %d", &a, &b)) {
        //先把二者之中的较小值放在左侧
        if (a > b) {
            int temp = a;
            a = b;
            b = temp;
        }
        if (a == b) {//包括0 0这种特殊情况
            printf("1\n");//先手必胜
        } else if (a == (int)((b-a)*((sqrt(5)+1)/2))){
            printf("0\n");//先手必输
        } else {
            printf("1\n");//先手必赢
        }
    }
    return 0;
}

你可能感兴趣的:(c语言)