您的位置:首页 > 其它

HDU 2177 取(2堆)石子游戏 (威佐夫博弈)

2016-10-16 16:02 441 查看


取(2堆)石子游戏

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 2280    Accepted Submission(s): 1384


Problem Description

有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。如果你胜,你第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

   思路:威佐夫博弈,遇到奇异局势则必败第k个奇异局势(a(k),
b(k)),a(k)是前面没有出现过的最小自然数(a(k)=(int)(k*(sqrt(5.0)+1)/2),b(k)=a(k)+k,采用适当的方法,这里不再证明,接下来只要判断就行了
同时从两堆中取相同数量的石头或者从一堆中取一定数量的石头,可以将非奇异局势变为奇异局势

#include <cstdio>
#include <cmath>
#include <algorithm>
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<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: