启发式A*算法解决最短路径问题

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*算法都是最短路径问题的常用算法,下面就对这两种算法的特点进行一下比较。

  1. Dijkstra算法计算源点到其他所有点的最短路径长度,A*关注点到点的最短路径(包括具体路径)。
  2. Dijkstra算法建立在较为抽象的图论层面,A*算法可以更轻松地用在诸如游戏地图寻路中。
  3. Dijkstra算法的实质是广度优先搜索,是一种发散式的搜索,所以空间复杂度和时间复杂度都比较高。对路径上的当前点,A*算法不但记录其到源点的代价,还计算当前点到目标点的期望代价,是一种启发式算法,也可以认为是一种深度优先的算法(估价函数最优),也可以认为是一种BFS+DFS的结合(估计值<真实值)。
  4. 由第一点,当目标点很多时,A*算法会带入大量重复数据和复杂的估价函数,所以如果不要求获得具体路径而需要比较路径长度时,Dijkstra算法会成为更好的选择。

参考:https://blog.csdn.net/dujuancao11/article/details/109749219

### 回答1: A*算法是一种常用于寻找最短路径的算法。下面给出一个万能通用的Matlab代码实现: ```matlab function shortestPath = A_star(startNode, goalNode, adjacencyMatrix, heuristic) numNodes = size(adjacencyMatrix, 1); % 获取节点数量 openSet = startNode; % 初始化开放集合 gScore = Inf(numNodes, 1); % 初始化gScore gScore(startNode) = 0; % 设置起始节点的gScore为0 fScore = Inf(numNodes, 1); % 初始化fScore fScore(startNode) = heuristic(startNode, goalNode); % 设置起始节点的fScore为启发式函数值 cameFrom = zeros(numNodes, 1); % 初始化cameFrom数组 while ~isempty(openSet) [~, current] = min(fScore(openSet)); % 从开放集合中选择fScore最小的节点作为当前节点 if current == goalNode shortestPath = reconstructPath(cameFrom, current); % 如果当前节点为目标节点,则重构路径并返回 return; end openSet(openSet == current) = []; % 从开放集合中移除当前节点 neighbors = find(adjacencyMatrix(current,:) > 0); % 获取当前节点的邻居节点 for i = 1:length(neighbors) neighbor = neighbors(i); tentativeGScore = gScore(current) + adjacencyMatrix(current, neighbor); % 从当前节点到邻居节点的距离 if tentativeGScore < gScore(neighbor) cameFrom(neighbor) = current; % 更新邻居节点的cameFrom gScore(neighbor) = tentativeGScore; % 更新邻居节点的gScore fScore(neighbor) = gScore(neighbor) + heuristic(neighbor, goalNode); % 更新邻居节点的fScore if ~ismember(neighbor, openSet) openSet(end+1) = neighbor; % 如果邻居节点不在开放集合中,则将其加入 end end end end error("No path found."); % 如果无法到达目标节点,则抛出错误 end function path = reconstructPath(cameFrom, current) path = current; while cameFrom(current) ~= 0 current = cameFrom(current); path = [current; path]; % 在路径之前添加上一个节点 end end ``` 上述代码实现了A*算法最短路径搜索。其中,`startNode`表示起始节点的索引,`goalNode`表示目标节点的索引,`adjacencyMatrix`表示节点间的邻接矩阵,`heuristic`表示启发式函数。函数输出为一个表示最短路径的向量,即从起始节点到目标节点的节点索引序列。 这个代码适用于任何可以表示为图的最短路径问题,只需提供相应的起始节点、目标节点、邻接矩阵和启发式函数即可。 ### 回答2: A*算法是一种用于寻找最短路径的启发式搜索算法,在许多应用中被广泛使用。下面我将给出一个使用MATLAB实现的通用A*算法代码: ```matlab function path = AStar(start, goal, heuristic, cost) openSet = start; % 初始化openSet队列,包含起点 closedSet = []; % 初始化closedSet队列,不包含任何节点 gScore = inf(size(cost)); % 初始化gScore为无穷大 gScore(start) = 0; % 起点的gScore为0 fScore = inf(size(cost)); % 初始化fScore为无穷大 fScore(start) = heuristic(start, goal); % 起点的fScore为启发式函数的值 while ~isempty(openSet) [~, current] = min(fScore(openSet)); % 在openSet中找到fScore最小的节点作为当前节点 current = openSet(current); if current == goal % 当前节点为目标节点 path = reconstructPath(cameFrom, current); return; end openSet(openSet == current) = []; % 将当前节点从openSet中删除 closedSet = [closedSet, current]; % 添加当前节点到closedSet for neighbor = find(cost(current, :)) % 遍历当前节点的邻居节点 if ismember(neighbor, closedSet) % 跳过已经在closedSet中的节点 continue; end tentativeGScore = gScore(current) + cost(current, neighbor); % 计算从起点到邻居节点的临时gScore if ~ismember(neighbor, openSet) % 如果邻居节点不在openSet中 openSet = [openSet, neighbor]; % 将邻居节点添加到openSet elseif tentativeGScore >= gScore(neighbor) % 如果临时gScore不小于邻居节点的gScore continue; % 跳过当前循环 end cameFrom(neighbor) = current; % 更新邻居节点的cameFrom指针 gScore(neighbor) = tentativeGScore; % 更新邻居节点的gScore fScore(neighbor) = gScore(neighbor) + heuristic(neighbor, goal); % 更新邻居节点的fScore end end error("No path found!"); % 如果循环结束时仍未找到路径,抛出错误异常 end function path = reconstructPath(cameFrom, current) path(1) = current; % 从目标节点出发 while cameFrom(current) ~= 0 % 当前节点存在指向的前驱节点 current = cameFrom(current); % 回溯节点 path = [current, path]; % 添加到路径中 end end ``` 上述代码实现了一个基本的A*算法,其中使用了启发式函数(heuristic)和代价函数(cost)来评估节点的值。在代码中,我们首先初始化openSet队列,然后在每一次迭代中选择fScore最小的节点作为当前节点,然后通过遍历当前节点的邻居节点来更新节点的gScore和fScore。最后,如果找到了路径,我们通过回溯(reconstructPath)来生成最短路径。 这段代码可以根据具体的应用场景进行一定的修改和优化。 ### 回答3: A*算法是一种常用的图搜索算法,可以用于求解最短路径问题。下面是一个用MATLAB实现的通用的A*算法代码: ```matlab function path = Astar(graph, start, goal) % 初始化起点和终点节点 startNode = Node(start, [], 0, heuristic(start, goal)); goalNode = Node(goal, [], inf, inf); % 初始化开启列表和关闭列表 openList = PriorityList(); closeList = {}; % 将起点节点加入开启列表 openList.add(startNode); % 当开启列表不为空时,继续搜索 while ~openList.isEmpty() % 从开启列表中获取最佳节点 currentNode = openList.removeFirst(); % 将当前节点加入关闭列表 closeList{end+1} = currentNode; % 如果当前节点是目标节点,则找到最短路径 if currentNode == goalNode path = reconstructPath(currentNode); return; end % 获取当前节点的所有相邻节点 neighbors = getNeighbors(graph, currentNode); for i = 1:length(neighbors) neighbor = neighbors(i); % 跳过已经在关闭列表中的节点 if isNodeInList(neighbor, closeList) continue; end % 计算从起点到这个相邻节点的已知最短路径 tentative_gScore = currentNode.gScore + getDistance(currentNode, neighbor); % 判断这个相邻节点是否已经在开启列表 if ~openList.contains(neighbor) openList.add(neighbor); elseif tentative_gScore >= neighbor.gScore continue; end % 更新相邻节点的父节点和路径代价 neighbor.parent = currentNode; neighbor.gScore = tentative_gScore; neighbor.fScore = neighbor.gScore + heuristic(neighbor.position, goal); end end % 若无法找到最短路径,返回空 path = []; end function path = reconstructPath(lastNode) path = []; while ~isempty(lastNode) path = [lastNode.position path]; lastNode = lastNode.parent; end end function neighbors = getNeighbors(graph, node) neighbors = []; for i = 1:size(graph, 1) if graph(node.position, i) ~= 0 neighbors = [neighbors Node(i)]; end end end function distance = getDistance(nodeA, nodeB) distance = graph(nodeA.position, nodeB.position); end function h = heuristic(position, goal) h = abs(position - goal); end classdef Node < handle properties position parent gScore fScore end methods function obj = Node(position, parent, gScore, fScore) obj.position = position; obj.parent = parent; obj.gScore = gScore; obj.fScore = fScore; end function result = eq(obj, other) result = obj.position == other.position; end end end classdef PriorityList < handle properties list end methods function obj = PriorityList() obj.list = {}; end function add(obj, item) for i = 1:length(obj.list) if item.fScore < obj.list{i}.fScore obj.list = [obj.list(1:i-1) item obj.list(i:end)]; return; end end obj.list{end+1} = item; end function removeFirst(obj) if ~isempty(obj.list) obj.list = obj.list(2:end); end end function result = isEmpty(obj) result = isempty(obj.list); end function result = contains(obj, item) result = false; for i = 1:length(obj.list) if obj.list{i} == item result = true; return; end end end end end ``` 以上代码实现了A*算法的一个通用版本,可以通过修改图的邻接矩阵、起点和终点来解决不同的最短路径问题
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weiambt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值