参考自:最短路径算法-迪杰斯特拉(Dijkstra)算法 - 知乎 (zhihu.com)
一、最短路径算法-迪杰斯特拉(Dijkstra)算法
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,基于广度优先算法BFS进行改进,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止
基本思想
- 指定起点D,引进数组S和U
- S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度)
- U的作用是记录还未求出最短路径的顶点(以及该顶点到起点D的距离)
- 初始时,数组S中只有起点D;数组U中是除起点D之外的顶点,并且数组U中记录各顶点到起点D的距离。如果顶点与起点D不相邻,距离为无穷大。
- 从数组U中找出路径最短的顶点K,并将其加入到数组S中;同时,从数组U中移除顶点K。接着,更新数组U中的各顶点到起点D的距离。
- 重复上一步步操作,直到遍历完所有顶点。
迪杰斯特拉(Dijkstra)算法图解
以上图为例,来对迪杰斯特拉进行算法演示(以顶点D为起点)。
二、贪婪优先算法
三、A*算法
A星算法核心公式就是F值的计算:
F = G + H
F - 方块的总移动代价
G - 开始点到当前方块的移动代价
H - 当前方块到结束点的预估移动代价
基本思想
(1)把起点加入 open list 。
(2)重复如下过程:
a. 遍历 open list ,查找 F 值最小的节点,把它作为当前要处理的节点。
b.把这个节点移到 close list 。
c.对当前方格的 8 个相邻方格的每一个方格?
◆ 如果它是不可抵达的或者它在 close list 中,忽略它。否则,做如下操作。
◆ 如果它不在 open list 中,把它加入 open list ,并且把当前方格设置为它的父亲,记录该方格的 F , G 和 H 值。
◆ 如果它已经在 open list 中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 G 值作参考。更小的 G 值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它的 G 和 F 值。如果你的 open list 是按 F 值排序的话,改变后你可能需要重新排序。
d. 停止,当你
◆ 把终点加入到了 open list 中,此时路径已经找到了
◆ 查找终点失败,并且 open list 是空的,此时没有路径。
(3)保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。
计算移动代价的方式
①曼哈顿距离
如果图形中只允许朝上下左右四个方向移动,则启发函数可以使用曼哈顿距离
②欧氏距离(L2距离):
③对角距离
如果图形中允许斜着朝邻近的节点移动,则启发函数可以使用对角距离
//计算到达终点的代价
//返回对角代价*x和y中的较小值+直线代价*x和y的差值
MOVE_DIAGONAL_COST =14;
MOVE_STRAIGHT_COST =10;
private int CalculateDistanceCost(GridObject a, GridObject b)
{
int X_Distance = Mathf.Abs(a.x - b.x);
int Y_Distance = Mathf.Abs(a.y - b.y);
int remaining = Mathf.Abs(X_Distance - Y_Distance);
return MOVE_DIAGONAL_COST * Mathf.Min(X_Distance,Y_Distance)
+ MOVE_STRAIGHT_COST * remaining;
}