A*算法:
在搜索的过程中,使用一个估价函数对当前点进行评估,找到最好的状态进行搜索,直到找到目标。
估价函数F(x)=G(x)+H(x)
,其中G(x)为实际代价,H(x)为启发函数,这就是启发式。并且启发函数要满足:H(x)<=H*(x),H*(x)为真实值,意思是启发函数的要求是必须小于等于真实值,启发函数的选取决定着A*算法的优劣,当启发值与真实值完全相等时,此时会达到最优的情况。
A*算法解决最短路问题
A算法是一种启发式算法,在最短路径问题上是对Dijkstra算法的优化,加入启发函数提高搜索的效率。
而本文当中使用A算法解决最短路径问题采用的启发函数是该点距离终点的最短距离,而计算该点距离终点的最短距离的方法是使用dijksta算法从终点作为起点跑一遍。事实上,使用dijkstra求得的启发函数就是真实值,也就是说这种情况搜索效率最高,也就退回了线性结构,从路径上看就是一条直线,类似DFS的轨迹。
- 代码如下:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 1010, M = 200010;
int n, m, S, T;
int h[N], rh[N], e[M], w[M], ne[M], idx;
int dist[N];
bool st[N];
//邻接表
void add(int h[],int a,int b,int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
//计算终点T到各点的最短距离作为启发函数
void dijkstra()
{
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,T});//从终点开始搜
memset(dist, 0x3f, sizeof dist);
dist[T] = 0;
while(heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.y;
if(st[ver]) continue;
st[ver] = true;
for(int i=rh[ver];i!=-1;i=ne[i])
{
int j = e[i];
if(dist[j]>dist[ver]+w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j],j});
}
}
}
}
int astar()
{
priority_queue<PIII, vector<PIII>, greater<PIII>> heap;//小根堆
// 谁的d[u]+f[u]更小 谁先出队列
heap.push({dist[S], {0, S}});
cout<<S;
while(heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.y.y,distance = t.y.x;
if(distance>0)
cout<<"->"<<ver;
if(ver==T){//搜到了
return distance;
}
for(int i=h[ver];i!=-1;i=ne[i])
{
int j = e[i];
// 按 真实值+估计值 = d[j]+f[j] = dist[S,t] + w[t][j] + dist[j,T] 堆排
// 真实值 distance+w[i]
heap.push({distance+w[i]+dist[j],{distance+w[i],j}});
}
}
return -1;
}
int main()
{
cin >> m >> n;
memset(h,-1,sizeof h);
memset(rh,-1,sizeof rh);
for(int i=0;i<n;i++)
{
int a,b,c;
cin >> a >> b >> c;
add(h,a,b,c);
add(rh,b,a,c);
}
cin >> S >> T;
// 从各点到终点的最短路距离 作为估计函数f[u]
dijkstra();
int ans=astar();
if(ans!=-1)
printf("\n从顶点%d到顶点%d的最短路径长度为:%d\n",S,T,ans);
else
printf("\n从顶点%d到顶点%d不存在最短路径",S,T);
return 0;
}
运行结果:
Dijkstra算法与A*算法比较
Dijkstra算法和A*算法都是最短路径问题的常用算法,下面就对这两种算法的特点进行一下比较。
- Dijkstra算法计算源点到其他所有点的最短路径长度,A*关注点到点的最短路径(包括具体路径)。
- Dijkstra算法建立在较为抽象的图论层面,A*算法可以更轻松地用在诸如游戏地图寻路中。
- Dijkstra算法的实质是广度优先搜索,是一种发散式的搜索,所以空间复杂度和时间复杂度都比较高。对路径上的当前点,A*算法不但记录其到源点的代价,还计算当前点到目标点的期望代价,是一种启发式算法,也可以认为是一种深度优先的算法(估价函数最优),也可以认为是一种BFS+DFS的结合(估计值<真实值)。
- 由第一点,当目标点很多时,A*算法会带入大量重复数据和复杂的估价函数,所以如果不要求获得具体路径而需要比较路径长度时,Dijkstra算法会成为更好的选择。
参考:https://blog.csdn.net/dujuancao11/article/details/109749219