51NOD 1185 威佐夫游戏 V2

 

 



首先,这个题目我本身就不太理解= =

第一堆为3 第二堆为5,那A先拿第一堆的3个,B拿第二堆的1个,A再拿四个不就是A赢了?

不过后来查了几个博客,发现这个是典型的威佐夫博弈问题。

so,只能从头去理解了。

这个博客总结了威佐夫博弈问题,可以参考

点击打开链接

   嗯,现在有了初步理解

现在一致先手必输的情况为:

(0,0)

(1,2)

(3,5)

(4,7)

(5,9) 

    ……

因此可以得出先手输掉的局面,第一堆和第二堆石子数量的差值为0,1,2,3,4……,为递增数列,且第一堆石子数量为前面

没有出现的最小自然数。(第一堆的数字必须是两者之间小的那一个,如果不是则需要交换位置)

并且奇妙的是,再找规律的话我们会发现,第一个值 = 差值 * 1.618 

而1.618 = (sqrt(5)+ 1) /  2 。

大家都知道0.618是黄金分割率。而威佐夫博弈正好是1.618,这就是博弈的奇妙之处!

因此这道题目前来说大概就明了了。

如果所输入的石子数,两者之间的差值乘以黄金分割率不等于第一个石子堆个数,则A赢,反之,则B赢。

   但是

事情远远没有这么简单

这道题有精度要求,所以不能直接简单去乘1.618

题目要求:石子数最多有18位,所以要把它分开= =

  第2 - T + 1行:每行2个数分别是2堆石子的数量,中间用空格分隔。(1 <= N <= 10^18)

具体实现:

上面提到,由于是大数,直接乘以(sqrt(5)+1)/2会有精度问题。

那么我们就来模拟一下两数之差和(sqrt(5)+1)/2相乘的过程,

它等价为:(b-a)*黄金分割比例+(b-a) . 

我们用tmp数组存储黄金分割比例的小数点后1~9位、10~18位、19~27位。

用l存储(b-a)的高9位,r存储(b-a)的低9位。

则两数相乘有:

                         tmp[0]       tmp[1]      tmp[2]

                   *                         l                r       

                        r*tmp[0]    r*tmp[1]     r*tmp[2]  

    +  l*tmp[0]    l*tmp[1]     l*tmp[2]

以上是模拟乘法的过程,只需要把每一位对应的数相加再加上低位,最后加上(b-a)即可。

   代码实现:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std; 
long long mod=1e9;
int main()
{
    int t;
    cin>>t;
    long long ratio[3]={618033988,749894848,204586834};
    while(t--)
    {
        long long num1,num2;
        cin>>num1>>num2;
        if(num1>num2)
        swap(num1,num2);
        long long cha=num2-num1;//
        long long r=cha%mod;//低九位 
        long long l=cha/mod;//高九位 
        //开始模拟 
        long long sum=r*ratio[2];//最低位
        sum=l*ratio[2]+r*ratio[1]+sum/mod;//倒数第二位 +最低位 
        sum=l*ratio[1]+r*ratio[0]+sum/mod;//倒数第三位 +倒数第二位 +最低位
        sum=cha+l*ratio[0]+sum/mod;//同理,由于ratio其实是小数点后位数,所以除了3次1e9 
        if(sum==num1) 
        cout<<"B"<<endl; 
        else
        cout<<"A"<<endl;
    } 
    return 0;
}

 

posted @ 2018-07-10 17:11  fantastic123  阅读(295)  评论(0编辑  收藏  举报