有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。如果你胜,你第1次怎样取子?
Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,且a<=b。a=b=0退出。
Output
输出也有若干行,如果最后你是败者,则为0,反之,输出1,并输出使你胜的你第1次取石子后剩下的两堆石子的数量x,y,x<=y。如果在任意的一堆中取走石子能胜同时在两堆中同时取走相同数量的石子也能胜,先输出取走相同数量的石子的情况.
Sample Input
1 2
5 8
4 7
2 2
0 0
Sample Output
0
1
4 7
3 5
0
1
0 0
1 2
威佐夫博弈;必败情况有(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)(9,15)等,公式有:
ak =[k(1+√5)/2];
bk= ak + k ,k=0,1,2,…n
可以看出,每两个数之间的差值对应一组确定的必败情况
对于输入数据,分情况讨论,
如果输入为一种必败情况,那么必败;
如果输入非必败情况,那么我们一定可以将其取成必败情况,因此必胜(如何取为必胜接下来讨论)
当非必败时:
输入a,b(a<=b),设其差值为k,e=[1+√5)/2];
如果可以两堆取相同个数构成必败,根据公式2,其差值为k,根据k可以算出其需要的a,
如果所给的a大于需要的a,那么只要减去一个值,a就能变成所需要的值,同时,因为输入的a,b差值为k需要的a,b差值也为k,所以减去的一定是一个相同的值,所以当(k
*e)<a时,一定有第一种解;
对于第二种解,我们可以尝试将b往下减,当b<a时,交换a,b,直到当其差值*e==必败情况输出;
代码:
#include <iostream>
#include <cmath>
#include <stack>
#include <stdio.h>
#include<cstring>
#include <algorithm>
#include<cstdlib>
typedef long long ll;
using namespace std;
int main()
{
double e=(1+sqrt(5.0))/2.0;
int a,b,k;
while(cin>>a>>b && (a||b))
{
if(a>b)swap(a,b);
k=b-a;
if(int(k*e)==a)cout<<0<<endl;
else
{
cout<<1<<endl;
if(int(k*e)<=a)
cout<<int(k*e)<<' '<<b-(a-int(k*e))<<endl;
for(int i=b;i>0;i--)
{
int k=i,aa=a;
if(k<aa)swap(aa,k);
if(int((k-aa)*e)==aa)
cout<<int((k-aa)*e)<<' '<<k-(aa-int((k-aa)*e))<<endl;
}
}
}
}