POJ 1067 取石子游戏 (威佐夫博奕,公式)

题意:

  有两堆石子,两个人轮流取石子。规定每次有两种取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。给定两堆石子数量,问先手的输赢?

思路:

设 a<b

  k=a-b

  x=(1 + sqrt(5)) / 2

若 a==k*x 则必输!否则,必胜。

  简单来讲,判断先手输赢靠的就两堆石子数量的差的大小,如果两堆之差乘以一个特定的数字,刚好就是小堆的数目,那么必输。

  这个特定的数字的神奇之处在哪?

  根号5即 sqrt(5) = 2.2360679774998

  x=(2.236+1)/2=1.618左右

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstdio>
 4 using namespace std;
 5 int main()
 6 {
 7     //freopen("input.txt", "r", stdin);
 8     int a, b;
 9     double x=(1+sqrt(5.0))/2;
10     while(cin>>a>>b)
11     {
12         if(a>b)
13         {
14             int tmp=b;
15             b=a;
16             a=tmp;
17         }
18         int k=b-a;
19         if(a==(int)(k*x+0.5)) //必输
20             cout<<"0"<<endl;
21         else
22             cout<<"1"<<endl;
23     }
24     return 0;
25 }
AC代码