思路:威佐夫博弈,遇到奇异局势则必败第k个奇异局势(a(k), b(k)),a(k)是前面没有出现过的最小自然数(a(k)=(int)(k*(sqrt(5.0)+1)/2),b(k)=a(k)+k,采用适当的方法,这里不再证明,接下来只要判断就行了
同时从两堆中取相同数量的石头或者从一堆中取一定数量的石头,可以将非奇异局势变为奇异局势
#include
#include
#include
using namespace std;
double g = (sqrt(5.0) + 1) / 2; // 黄金分割数1.618...
int main()
{
int a, b;
while(scanf("%d %d", &a, &b) == 2) {
if(a == 0 && b == 0)
break;
int k = b - a;
if(a == (int)(g * k)) // 只要判断a即可,因为b=a+k是恒成立的
{
printf("0\n");
}
else
{
printf("1\n");
// 将非奇异局势变为奇异局势
for(int i=1; i<=a; i++) // 同时从两堆中取相同数量的石头,注意这里是从1到a枚举
{
int x = a - i, y = b - i;
int k = y - x;
if(x == (int)(g * k))
printf("%d %d\n", x, y);
}
for(int i=b-1; i>=0; i--) // 从一堆中取一定数量的石头,这里是从b-1往下枚举到0
{
int x = a, y = i;
if(x > y)
swap(x, y);
int k = y - x;
if(x == (int)(g * k))
printf("%d %d\n", x, y);
}
}
}
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
int vis[1000005]= {0};
int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
for(int i=1; i<1000005; i++)
vis[i]=(int)(i*1.0*(1+sqrt(5))/2);
int n, m;
while(scanf("%d%d",&n,&m)&&(n||m))
{
int k=m-n;
if(vis[k]==n)
{
printf("0\n");
continue;
}
printf("1\n");
if(n>vis[k]&&m>vis[k]+k)
printf("%d %d\n",vis[k],vis[k]+k);
for(int i=1; i<1000005; i++)
if(vis[i]==n)
{
if(m>vis[i]+i)
printf("%d %d\n",vis[i],vis[i]+i);
break;
}else if(vis[i]==m)
{
if(n>vis[i]+i)
printf("%d %d\n",vis[i],vis[i]+i);
break;
}
for(int i=1; i<1000005; i++)
if(vis[i]+i==m)
{
if(n>vis[i])
printf("%d %d\n",vis[i],vis[i]+i);
break;
}else if(vis[i]+i==n)
{
if(m>vis[i]+i)
printf("%d %d\n",vis[i],vis[i]+i);
break;
}
}
return 0;
}