zoukankan      html  css  js  c++  java
  • poj 1067 取石子游戏

    Poj中少有的中文题。这题其实有个术语叫“威佐夫博弈”,我当初找规律时试过二进制、斜率,没想到第三次试黄金分割就对了。

         说说我的思路吧,我会尽量用通俗的语言,因为有时候看到术语我会头晕。这题属于最简单的博弈类型,“状态争夺”,就是只有两个人,要想赢就要抢夺一个特殊状态,而一般谁面对这个状态谁倒霉,所以要把这个留给对手,它的术语叫“必败态”。举个例子,一堆石子,每次能拿走1,2,3块,两人轮流拿,取走最后所有石子的人胜。那必败态就是石子数为4n,对方面对这个状态,无论怎么取,你都能相应地取来维持数量为4的倍数,直到只剩4个,然后呢?没有然后了。顺便说一下,结束的状态也属于必败态,比如没有石子了,而0也是4的倍数。一般做这种题找必败态的规律是关键。

         然后说下必败态的两个性质,这非常重要。从刚刚那个例子能看出来,“维持”是关键,这就是性质1:必败态经过两次操作一定能回到必败态上。性质2是用来判断必败态的:必败态经过一次操作后一定不是必败态。如果改变以后还是必败态,那事情就狗血了:两个人你来我往,你给我一个必败,我给你一个必败,于是两个人都输了。所以,如果找规律的时候遇上这种情形,骚年,抓紧换个思路吧。

      这题其实很简单,给你一对数,判断是不是必败态。题目中的状态就是一对非负整数,可以把它们对应到二维坐标第一象限里的整点,而且(a,b)和(b,a)是等价的,操作就是把整点向左、下 or 左下方向移动到另一个整点。样例中给了两个必败态,(1,2)和(4,7),加上一个隐含的(0,0),也只有3个。要想从这么几组数据里找到规律是很蛋疼的事情,所以还是多找几个必败态先。这3组数据的差分别为0、1、3,于是推测在7*7范围内应该有一个差为2的必败态,下面画图找。

      如图,先在坐标系中找到(0,0)、(1,2)、(2,1)、(4,7)、(7,4),以它们为起点向右、上及右上方向作射线,根据性质2,射线上的点不可能是必败态,这样排除一大堆状态,再加上差为2,就只剩下(3,5)和(5,3)了。

      必败态的转化:

      根据从(0,0)到(4,7)的规律,第 i 个必败态F(i)=(a,a+i),a是未出现的数中最小的。于是找到了一大堆必败态:(6,10)、(8,13)、(9,15)、(11,18),(12,20)……剩下的就是找 i 和 a的关系了。

      当时我首先想到的是二进制,于是把它们化为二进制求& 、|、^、 ~ ,可是毫无规律。后来又发现相邻两个必败态之间作向量,只有(1,2)和(2,3)两种可能,于是猜想必败态对原点的斜率都在1/2和2/3之间,可是这中间还有好多数呢。后来鬼使神差地我想到了黄金比,没想到还真对了,a == [ i * 黄金比 ],[]表示取整。关于这个结论的证明,请自行度娘。

     1 #include <stdio.h>
     2 const double L = 1.6180339887;
     3 int main()
     4 {
     5     long long a,b,det;
     6     while(~scanf("%lld %lld",&a,&b))
     7     {
     8         if(a > b) a^=b^=a^=b;
     9         det = b-a;
    10         if(a == int(det * L))
    11             printf("0\n");
    12         else printf("1\n");
    13     }
    14     return 0;
    15 }

      直接看代码的话,真的好水,可是这背后的苦逼思考可不是水的。

  • 相关阅读:
    思维科学的层次和学科构成
    知识管理--要对自己的知识做顶层的梳理和管理
    深入分析泛型编程--编译器使用模版生成代码
    算法与上下文
    深入理解递归算法
    什么是递归:递 与 归
    分治与”分析与综合”
    分治的逻辑学描述
    分治与递归
    generator的本质是将异步的管理剥离
  • 原文地址:https://www.cnblogs.com/lzxskjo/p/2661112.html
Copyright © 2011-2022 走看看