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