Astar 搜索算法

Astar A* 算法路径搜索应用

在求解路径问题时,往往会搜索许多不必要的路径,计算机无法简单地实现人的宏观思维

所以,可以给当前需要搜索的路径增设一个估价函数,令计算机判断当前的最优解,这样可以节省许多不必要的时间开支

估价函数预处理出每个状态到目标状态的所需代价的估计值 \(f(x)\),实际值为 \(g(x)\),应当满足估计值不大于实际值 \(f(x)\le g(x)\) (越接近越准确),这样的带有估价函数的优先队列 BFS 叫做 Astar 算法


在 BFS 过程中,维护一个堆,每次取出堆中 当前代价+未来估价 的最小状态进行扩展

例如求解第 \(K\) 短路问题:给定 \(n\) 个节点与 \(m\) 条边的有向图,求从 \(s\)\(t\) 的第 \(K\) 短路

未来估价函数的计算

\(f_i\) 表示第 \(i\) 个节点到 \(t\) 的距离,这里可以通过 Dijkstra 算法,以 \(t\) 为起点 \(s\) 为终点跑一遍,最后可以计算出精确的 \(f_i=g_i\)

注意需要额外存一张反向图,这里以 rhe 表示

struct edge{
long long v,w;
};
vector<edge> rhe[5010];
void dijkstra(void){
priority_queue<pair<long long,long long>> q;
memset(f,0x3f,sizeof f);
f[t]=0;
q.push({0,t});
while (q.size()){
auto t=q.top();
q.pop();
if (vis[t.second]) continue;
vis[t.second]=1;
for (auto iter:rhe[t.second]){
if (f[iter.v]>f[t.second]+iter.w){
f[iter.v]=f[t.second]+iter.w;
q.push({-f[iter.v],iter.v});
}
}
}
}

Astar的实现

正向跑一边优先队列的 BFS,堆中维护三元组 \(\{dis_{s,i}+f_i,i,d\}\),按照 \(dis_{s,i}+f_i\) 从小到大排序

分别表示: \(s\)\(i\) 的距离 + \(i\)\(t\) 的未来估价函数,\(i\) 点编号,\(d\) 记录的总路径长度

在过程中,我们只允许每个点最多入队 \(K\) 次,当 \(t\) 节点第 \(K\) 次出队时,对应三元组中的 \(d\) 就为所求的第 \(K\) 短路

long long astar(void){
priority_queue<node> q;
q.push({f[S],S,0});
while (q.size()){
auto t=q.top();
q.pop();
cnt[t.v]++;
if (cnt[T]==K)//终点出队k次
return t.d;
for (auto iter:he[t.v])
if (cnt[iter.v]<K)
q.push({t.d+iter.w+f[iter.v],iter.v,t.d+iter.w});
}
return -1;
}

如果需要求严格的第 \(K\) 短路,即当路径长度不同时才算为不同的第 \(K\) 短路,需要增设一个变量记录上一次的答案

如果这一次得到路径长度与上一次相同,那么就需要令 \(K+1\)(当前的路径无效)

struct node{
long long s,v,d;
bool operator<(const node&x)const{
return s>x.s;
}//重载运算符,使优先队列按照s从小到大排列
};
long long mem=-1;
long long astar(void){
priority_queue<node> q;
q.push({f[s],s,0});
while (q.size()){
auto t=q.top();
q.pop();
if (t.v==K){
if (mem==t.d) K++;
else mem=t.d;
}
cnt[t.v]++;
if (cnt[T]==K)
return t.d
for (auto iter:he[t.v])//he表示正向图
if (cnt[iter.v]<K)
q.push({t.d+iter.w+f[iter.v],iter.v,t.d+iter.w});
}
return -1;
}
posted @   才瓯  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示