hdu 2177 取(2堆)石子游戏 博弈论

时间:2023-03-09 02:59:02
hdu 2177 取(2堆)石子游戏 博弈论

由于要输出方案,变得复杂了。数据不是很大,首先打表,所有whthoff 的奇异局势。

然后直接判断是否为必胜局面。

如果必胜,首先判断能否直接同时相减得到。这里不需要遍历或者二分查找。由于两者同时减去一个数,他们的差不变,而且ak=k*(sqrt(5)+1),bk=ak+k;

则可以通过二者的差直接定位,然后判断。

对于另外一种情况,其中一个减去某个数,得到奇异局势,则是分情况二分查找。

注意一些细节

代码如下:

 #include<stdio.h>
#include<cmath>
#include<algorithm>
#define M 1000002
using namespace std;
int a[M/],b[M/],cnt;
void fun1(int n,int m)
{
int l=,r=cnt,mid;
while(l<=r){
mid=(l+r)>>;
if(n==a[mid]){
if(m>b[mid])
printf("%d %d\n",a[mid],b[mid]);
return;
}
if(n>a[mid])
l=mid+;
else r=mid-;
}
}
void fun2(int n,int m)
{
int l=,r=cnt,mid;
while(l<=r){
mid=(l+r)>>;
if(n==b[mid]){
if(m>a[mid])
printf("%d %d\n",a[mid],b[mid]);
return;
}
if(n>b[mid])
l=mid+;
else r=mid-;
}
}
int main(){
int n,m,i;
for(i=;i<=;i++){
a[i]=(int)(i*(sqrt(5.0)+1.0)/2.0);
b[i]=a[i]+i;
if(b[i]>=){
cnt=i;
break;
}
}
while(scanf("%d%d",&n,&m)&&(n+m)){
if(n<m) swap(n,m);
int t=(int)((n-m)*(sqrt(5.0)+)/2.0);
if(m==t) printf("0\n");
else{
printf("1\n");
if(n-m<cnt&&m-a[n-m]==n-b[n-m])
printf("%d %d\n",a[n-m],b[n-m]);
fun1(m,n);
if(n!=m) fun1(n,m);
fun2(m,n);
if(n!=m) fun2(n,m);
}
}
return ;
}