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左右

a或者b上限是10亿,那么两者之差上限也是10亿,有9个0在后面,所以至少需要精确到9位以上。而double保存的实数的精确值是不确定的,在转成int时会上下浮动1。

也许数据就是按照不精确的方式筛选出来的,所以答案也没有那么精确吧?

要不然就是数据刚好碰到的是正确的答案,测不出那些double精确问题。数据是用精确度高的大数方法筛选出来的,然后再用不精确的方式计算一遍这些数据,错误的就去掉,这样子就保证了方法正确的人能计算出这些数字了(但精确度不高的)。

 

 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代码

 

你可能感兴趣的:(poj)