离散报告
题选:图的最短路径算法,A*算法
求解最短路径的算法有很多,而A*算法无疑是其中最高效率、适用性更强的算法之一。
概括来说 A*算法=贪心最优搜索+BFS+优先队列=贪心+Dijkstra+优先队列
A*算法的核心在于估价函数 f=g+h,其效率取决于H函数的设计
1.贪心最优搜索
贪心是启发式算法,在寻找图中最短路径时能高效找到局部最优解,但无法保证全局最优解
具体的实现思想:从起点s出发,寻找i点(i点是距离终点t最近的邻居节点)
如何找距离终点最近的邻居节点i?如何估计i到t的距离?
BFS+优先队列;我们用曼哈顿距离估算最短距离。
然而,这样的贪心算法无法确保我们假定的最优解存在。我们分情况讨论:
- 在无障碍网格中,贪心结果是最优解。因为曼哈顿距离一定存在
- 在有障碍网格图中,曼哈顿距离不一定存在,可能i节点在走曼哈顿距离时碰壁,回头绕路。因此,在有障碍网格图中,我们不能确保贪心得到存在的最优解。
然而,无障碍网格图要求这是个连通图,这样大量图无法适用于贪心法。
总结来看:贪心最优搜索,只看终点,不看起点,错了不能改正,没有回头路,而且曼哈顿距离无法绕过障碍
2.Dijkstra(BFS)算法
优先队列的Dijkstra 算法能够高校球的起点s到终点t的距离,但是Dijkstra有bfs通病:没有方向,一股脑一层一层往下。但我们需求只有求一条s到t的最短路径,而不是s到图的任意节点的最短路径,这样会遍历大量的节点空间造成浪费。
总结来看:Dijkstra,只看起点,不看终点
A*算法
其实很多高效复杂的算法都是针对同一种问题基本的不同算法的杂交。举个例子,在探究图的连通性时,我们会用到加权快速并集和路径压缩快速并集,很自然地,将两者结合,我们就会想到Weighted quick-union with path compression
同理,A算法也是两种基本解决最短路径算法的结合,贪心和Dijkstra,总结来看,*既看起点,也看终点,这恰好互补了两种基本算法的缺陷。
我们用曼哈顿方法作为计算距离的方法 算法代码实例(c++)
1 |
|
那这是如何结合两种算法的?
- 对于起点s到i的路径,Dijkstra保证最优性
- 对于i到t的路径,采用贪心预测,选择i的下一个节点。
- 当i碰壁时,i被丢弃;回退到上一层重新选择节点j,而j任由Dijkstra保证最优性
对于以上具体实现想法,我们设计一个函数抽象的表示: f(i)=g(i)+h(i) (g反映Dijkstra,h反映贪心)
- 显然,g=0,A 退化成贪心;h=0,A退化成Dijkstra
详细解释一遍:A*更具最小的f(i)选择下一个节点i,g(i)是走过的路径,已知;h(i)是预测未来走的路径,f(i)取决于h(i)的计算
A*的结果一定是最优吗?
当i到t终点时,h(t)=0,此时f(t)=g(t),而g(t)是由Dijstra保证的最短路径,因此A*能够得出最优解
总的来说,A*以Dijkstra获得最优结果,用贪心扩展方向,大大减少搜索的节点
h函数设计
对于二维平面图,三种办法近似计算h函数,设i的坐标(x1,x2),t(x2,y2)
- 曼哈顿距离。节点只能上下左右移动,h(i)=abs(x1-x2)+abs(y1-y2)
- 对角线距离,节点能够8个方向上移动(新增东北,西北,东南,西南方向),h(i)=max{abs(x1-x2),abs(y1-y2)}
- 欧式距离,节点可以任意方向移动,h(i)=sqrt((x1-x2) 2+(y1-y2) 2)
注意三条规则
- g和h采用相同距离计算方法
- 根据具体图的背景信息,选择相应的距离算法
- h优于实际存在的所有路径,这一点很关键,接下来我们会对此具体讨论
1.h(i) > i-t中存在的最短路径长度。设实际最短路径为path,由于计算h(i)扩展下一个节点,path被抛弃了(因为找到h(i)),选择非最短路径
- h(i) < i-t中所有路径。这意味着在i-t中不存在长度为h(i)的路径,在搜寻h(i)的路径时,节点一定会碰壁。但这不要紧,因为Dijkstra算法让这些碰壁的点弹出,回退到合适的点,从而扩展出实际路径。
参考:https://blog.csdn.net/denghecsdn/article/details/78778769
A*算法例题
from poj 2249
题面描述:
给定N个点,M条有向边。给出起点s和终点t,求其中第K个最短路径。
注意:若出发点与结束点为同一点,则一定要从出发点跑出去,再跑回来,才算最短路
第K短路则运用了A ∗ AA∗的排除多余状态与优先队列B F S BFSBFS,第几次取出e d eded,即求到第几短路的性质来解决问题,A ∗ AA∗主要起优化作用。
1 |
|