欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
这道 A* \operatorname{A*} A*题貌似用 map \operatorname{map} map会被卡,
手打 hash \operatorname{hash} hash吧。
我们要用hash来判重。
避免不必要的重复状态。
struct hashmap
{
bool v[N<<1];
struct edge
{
int x,y,next,p;
edge(){}
}a[N<<1];int len;int last[N<<1];
hashmap(){}
inline bool ins(int p,int x,int y)
{
int u=(x*y)%mod;
for(int k=last[u];k;k=a[k].next)
{
if(a[k].x==x&&a[k].y==y)
{
if(a[k].p>p){a[k].p=p;return true;}
return false;
}
}
a[++len].x=x,a[len].y=y;a[len].next=last[u];last[u]=len;a[len].p=p;
return true;
}
}h;
貌似用 exbsgs \operatorname{exbsgs} exbsgs的 hash \operatorname{hash} hash表会被卡。
为了避免状态重复,我们进行一些剪枝:
- 保证 a ≥ b a\ge b a≥b,这样可以在hash表中避免重复。
- 保证 a , b a,b a,b小于数据范围
- 保证 n m o d    gcd ( a , b ) = = 0 n \mod \gcd(a,b)==0 nmodgcd(a,b)==0,时才能继续进行。
简要证明一下第3条
若 n m o d    gcd ( a , b ) ! = 0 n\mod \gcd(a,b)!=0 nmodgcd(a,b)!=0因为无论如何, a , b a,b a,b怎么乘怎么除都不可能等于 n n n.
估价函数为,把 a a a不断自加直至 ≥ n \ge n ≥n所需的次数(注意 a ≥ b a\ge b a≥b)
显然实际所需次数不会小于这一次数。(此处借鉴算法进阶)
接着就是直接暴力枚举一下状态就行了。
AC code
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e6;
const int mod=999983;
const int inf=32767;
struct node
{
int a,b,val,cnt;
node(){}
node(int a,int b,int val,int cnt):a(a),b(b),val(val),cnt(cnt){}
bool operator <(const node a)const{return val==a.val?cnt>a.cnt:val>a.val;}
};
priority_queue<node>q;
int n;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int calc(int a,int b)
{
int val=0;
for(;a<n;a*=2)val++;
return val;
}
struct hashmap
{
bool v[N<<1];
struct edge
{
int x,y,next,p;
edge(){}
}a[N<<1];int len;int last[N<<1];
hashmap(){}
inline bool ins(int p,int x,int y)
{
int u=(x*y)%mod;
for(int k=last[u];k;k=a[k].next)
{
if(a[k].x==x&&a[k].y==y)
{
if(a[k].p>p){a[k].p=p;return true;}
return false;
}
}
a[++len].x=x,a[len].y=y;a[len].next=last[u];last[u]=len;a[len].p=p;
return true;
}
}h;
void add(int a,int b,int cnt)
{
if(a<b)swap(a,b);
if(a>inf||b>inf)return ;
if(n%gcd(a,b))return ;
bool bk=h.ins(cnt,a,b);
if(bk)q.push(node(a,b,calc(a,b)+cnt,cnt));
}
int astar()
{
add(1,0,0);h.len=0;
while(!q.empty())
{
node t=q.top();q.pop();
if(t.a==n||t.b==n)return t.cnt;
add(t.a*2,t.b,t.cnt+1);
add(t.a,t.b*2,t.cnt+1);
if(t.a)add(t.a*2,t.a,t.cnt+1);
if(t.b)add(t.b*2,t.b,t.cnt+1);
if(t.a-t.b>=0)add(t.a-t.b,t.a,t.cnt+1),add(t.a-t.b,t.b,t.cnt+1);
if(t.b-t.a>=0)add(t.b-t.a,t.a,t.cnt+1),add(t.b-t.a,t.b,t.cnt+1);
add(t.a+t.b,t.b,t.cnt+1);
add(t.a+t.b,t.a,t.cnt+1);
}
}
int main()
{
scanf("%d",&n);printf("%d\n",astar());
return 0;
}