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]=0a[k]=前面未出现的最小自然数,b[k]=a[k]+k
具体求解公式:a[k]=k1+52b[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 <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

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;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/idealism_xxm/article/details/51969730
个人分类: POJ 博弈论
想对作者说点什么? 我来说一句
相关热词

没有更多推荐了,返回首页

关闭
关闭
关闭