题目:http://acm.hdu.edu.cn/showproblem.php?pid=2177
相关算法:http://blog.csdn.net/a0210077/archive/2010/01/22/5223105.aspx
#include <iostream>
#include <queue>
using namespace std;
const double d=1.6180339887498948482045; //黄金矩形的长宽比
const int MAX=381967;
int t[MAX+1][2]={{0,0}}; //共有381968个必输组合,{0,0}算输,[差距][石子]
int a,b,margin;
int i,j,temp;
void count(){ //计算必输组合
temp=0,i=1;
a=1,b=2;
queue<int>q;
while(b<=1000000){
q.push(b);
t[i][0]=a;
t[i][1]=b;
if(a>temp){
temp=q.front();
q.pop();
}
if(a+1==temp){
a+=2;
b+=3;
}else{
a++;
b+=2;
}
i++;
}
}
void search(int now, int take){
bool found=false;
i=int(now/d); //搜索前数
while(i<=MAX && t[i][0]<=now){
if(t[i][0]==now){
found=true;
break;
}
i++;
}
if(!found){
i=int(now/d/d); //搜索后数
while(i<=MAX && t[i][1]<=now){
if(t[i][1]==now){
found=true;
break;
}
i++;
}
}
if(found){
if(t[i][0]==now && t[i][1]<take || t[i][1]==now && t[i][0]<take) //判断是否真的取走石子
printf("%d %d/n",t[i][0],t[i][1]);
}
}
void result(){
if(margin!=0 && margin<=MAX && a==t[margin][0] && b==t[margin][1]) //判断是否为必输状态,差距超过381968判定为胜利
printf("0/n");
else{
printf("1/n");
if (margin<=MAX && a>t[margin][0]) //是否能2堆石子一起取,达到必输状态
printf("%d %d/n",t[margin][0],t[margin][1]);
if (a==2 && b==2){ //除开2,2,当2堆石子数相同时不存在取1堆石子到达必输状态
printf("1 2/n");
}else if (margin!=0){
search(a,b); //搜索小堆石子不动,取大堆石子的方案
search(b,a); //搜索大堆石子不动,取小堆石子的方案
}
}
}
int main(int argc, char* argv[])
{
count();
while(1){
scanf("%d%d",&a,&b);
if (a==0 && b==0)
break;
if (a>b){ //a小b大
temp=a;
a=b;
b=temp;
}
margin=b-a;
result();
}
return 0;
}