这个题目用了启发式搜索来做,hash判重,优先队列储存节点。启发式函数就是大的数字x*2^k>n,即为k。
x为节点中较大值,y为节点中较小值
然后后面就是一些剪枝了,当x>2*n不能得出最优解。当y==0,不能得出最优解。当x==y,不能得出最优解。
还有一个比较关键的剪枝,gcd(x,y)不能整除n时,得不出结果。
#include
#include
#include
#include
#include
using namespace std;
const int maxn=160000+10;
int n;
int d[22222];
int time;
struct node
{
int x,y,h,cost;
bool operator <(const node &xx) const
{
return(cost>xx.cost);
}
};
priority_queue que;
int hash[maxn],lon;
struct
{
int x,y,cost,next;
}data[11111111];
void insert(struct node *p)
{
inttmp=p->x+p->y;
data[++lon].x=p->x;
data[lon].y=p->y;
data[lon].cost=p->h;
data[lon].next=hash[tmp];
hash[tmp]=lon;
}
int gcd(int a,int b)
{
int tmp;
while(a%b)
{
tmp=a%b;
a=b;
b=tmp;
}
return(b);
}
int check(int x,int y,int h)
{
if(x<=0)return(0);
if(y!=0)
if(n%gcd(x,y)!=0)
{
return(0);
}
if(x==n||y==n)
{
printf("%d\n",h);
exit(0);
}
if(x
swap(x,y);
if(x>n&&y>n) return(0);
if(x>n*2)return(0);
if(x>n&&y==0)return(0);
if(x==y)return(0);
for(intk=hash[x+y];k!=-1;k=data[k].next)
{
if(data[k].x==x&&data[k].y==y)
{
if(data[k].cost>h)
{
data[k].cost=h;
return(1);
}
else
return(0);
}
}
return(1);
}
int cal(int x,int y)
{
if(x==n)
return (0);
if(x
return(d[x]);
if(x>n)
{
int k=1;
int tmp=x-n;
while(y
{
k++;
y<<=1;
}
return(k);
}
}
void work(int x,int y,int h)
{
if(x
swap(x,y);
struct node p;
p.x=x;
p.y=y;
p.h=h;
p.cost=h+cal(x,y);
insert(&p);
que.push(p);
}
int bfs()
{
while(!que.empty())
que.pop();
memset(hash,-1,sizeof(hash));
lon=0;
struct node p;
p.x=1;
p.y=0;
p.h=0;
p.cost=p.h+cal(1,0);
insert(&p);
que.push(p);
while(!que.empty())
{
intx=que.top().x,y=que.top().y,h=que.top().h+1,cost=que.top().cost;
que.pop();
if(x==n||y==n)
return(cost);
if(check(x+y,y,h))
work(x+y,y,h);
if(check(x,x+y,h))
work(x,x+y,h);
if(check(x+x,y,h))
work(x+x,y,h);
if(check(x,x+x,h))
work(x,x+x,h);
if(check(y+y,y,h))
work(y+y,y,h);
if(check(y+y,x,h))
work(y+y,x,h);
if(check(x-y,y,h))
work(x-y,y,h);
if(check(x,x-y,h))
work(x,x-y,h);
}
}
int main()
{
scanf("%d",&n);
for(inti=n,j,t=0;i>=1;i=j)
{
j=i/2,t++;
for(int k=i-1;k>j;k--)
d[k]=t+1;
d[j]=t;
}
bfs();
return 0;
}