poj - 1067 取石子游戏

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

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

     而后说下必败态的两个性质,这很是重要。从刚刚那个例子能看出来,“维持”是关键,这就是性质1:必败态通过两次操做必定能回到必败态上。性质2是用来判断必败态的:必败态通过一次操做后必定不是必败态。若是改变之后仍是必败态,那事情就狗血了:两我的你来我往,你给我一个必败,我给你一个必败,因而两我的都输了。因此,若是找规律的时候赶上这种情形,骚年,抓紧换个思路吧。spa

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

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

  必败态的转化:blog

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

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

 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 }

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

转载于:https://www.cnblogs.com/lzxskjo/archive/2012/08/29/2661112.htmlim