POJ-1067 取石子游戏(威佐夫博弈)

题目链接

POJ-1067 取石子游戏

题目大意

有两堆石子,数量分别为\(a,b\),两个人轮流取石子。每次有两种不同的取法:一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最优策略,问最后你是胜者还是败者?

Sample Input

2 1
8 4
4 7

Sample Output

0
1
0

思路

直接是:威佐夫博弈。
这个过于繁琐,只能运用现成的结论。
设奇异局势(必败局势)为 (a[i],b[i]) ,则有 a[0]=b[0]=0 a[k]= 前面未出现的最小自然数, b[k]=a[k]+k
具体求解公式: a[k]=k1+52 b[k]=a[k]+k=k3+52

奇异局势的性质:
1.任何自然数包含在且仅包含在一个奇异局势中
a[k]>a[k1] b[k]=a[k]+k>a[k1]+k1=b[k1]>a[k1] ,则任意奇异局势中不存在相同的自然数(除了 (0,0) ),又 a[k] 前面未出现的最小自然数,则任何自然数均会出现在奇异局势中
2.任意操作均为将奇异局势变为非奇异局势
①在一堆中取石子,由于另一堆中的数不会出现在其他奇异局势中,则新局势必定非奇异局势
②在两堆中同时取石子,由于两堆石子差值不变,而序号为差值的奇异局势唯一,则新局势必定非奇异局势
3.任意非奇异局势可以通过特定操作转化为奇异局势
设当前局势为 (a,b)
a==b 时:同时从两堆取走 a 个石子,转化为 (0,0)
a==a[k]&&b>b[k] 时:从第二堆取走 bb[k] 个石子,转化为 (a,b[k])
a==a[k]&&b<b[k] 时:同时从两堆取走 aa[ba] 个石子,转化为 (a[ba],ba+b[ba])
a>a[k]&&b==b[k] 时:从第一堆取走 aa[k] 个石子,转化为 (a[k],b)
a<a[k]&&b==b[k] 时:若 a==a[j] (j<k) ,则从第二堆取走 bb[j] 个石子,转化为 (a,b[j]) ;否则必有 a==b[j](j<k) ,则从第二堆取走 ba[j] 个石子,转化为 (a[j],a)

代码

#include 
#include 
#include 
#include 

using namespace std;

int a,b,aa;
double x;

int main() {
    x=(1.0+sqrt(5.0))/2.0;
    while(2==scanf("%d%d",&a,&b)) {
        if(a>b) {
            swap(a,b);
        }
        aa=floor((b-a)*x);//计算第b-a个奇异局势
        printf("%d\n",a==aa?0:1);
    }
    return 0;
}

你可能感兴趣的:(POJ,博弈论)