赞
踩
与Dijkstra算法类似,A*算法结合了贪心算法(深度优先)和Dijkstra算法(广度优先),是一种启发式算法。
路径评价标准是:f(n) = g(n)+h(n)
f(n)是从初始点经过状态N到目标点的代价估计
g(n)是初始点到状态n的实际代价
h(n)是从状态n到目标点的代价
也是使用两个状态表,一个寄存待考察的状态点,一个寄存已经考察的状态点,类似Dijkstra中的U和S列表
1.将地图栅格化,把每一个正方形格子的中央称为节点;
2.确定栅格属性,即每一个格子有两种状态:可走和不可走
3.定义两个列表集合:openList和closeList。openList表由待考察的节点组成, closeList表由已经考察过的节点组成。类似Dijikstra算法的U集合和S集合。
4.确定起始节点和目标节点。
5.初始时,定义A为父节点,节点A离自身距离为0,路径完全﹔确定,移入closeList中;
6.父节点A周围共有8个节点,定义为子节点。将子节点放入i openList中,成为待考察对象。
7.若某个节点既未在openList,也没在closeList中,则表明还未搜索到该节点。若某个节点在openList中,则对比取f小的。
8.路径优劣判断依据是移动代价,单步移动代价采取Manhattan计算方式,即把横向和纵向移动一个节点的代价定义为10。斜向移动代价参考等腰三角形计算斜边的方式∶,距离为14。
- while 1:
- if len(open_set) == 0:
- print("Open set is empty..")
- break
-
- c_id = min(
- open_set,
- key=lambda o: open_set[o].cost + self.calc_heuristic(goal_node,
- open_set[
- o]))
- current = open_set[c_id]
-
- # show graph
- if show_animation: # pragma: no cover
- plt.plot(self.calc_grid_position(current.x, self.min_x),
- self.calc_grid_position(current.y, self.min_y), "xc")
- # for stopping simulation with the esc key.
- plt.gcf().canvas.mpl_connect('key_release_event',
- lambda event: [exit(
- 0) if event.key == 'escape' else None])
- if len(closed_set.keys()) % 10 == 0:
- plt.pause(0.001)
-
- if current.x == goal_node.x and current.y == goal_node.y:
- print("Find goal")
- goal_node.parent_index = current.parent_index
- goal_node.cost = current.cost
- break
-
- # Remove the item from the open set
- del open_set[c_id]
-
- # Add it to the closed set
- closed_set[c_id] = current
-
- # expand_grid search grid based on motion model
- for i, _ in enumerate(self.motion):
- node = self.Node(current.x + self.motion[i][0],
- current.y + self.motion[i][1],
- current.cost + self.motion[i][2], c_id)
- n_id = self.calc_grid_index(node)
-
- # If the node is not safe, do nothing
- if not self.verify_node(node):
- continue
-
- if n_id in closed_set:
- continue
-
- if n_id not in open_set:
- open_set[n_id] = node # discovered a new node
- else:
- if open_set[n_id].cost > node.cost:
- # This path is the best until now. record it
- open_set[n_id] = node
-
- rx, ry = self.calc_final_path(goal_node, closed_set)
-
- return rx, ry
代码讲解:
A*算法的代码实现与Dijkstra类似,不同点在于代价函数不一样,所以在计算U集合中的代价最小点的时候要考虑h和g。
- def searching_control(start, end, bound, obstacle):
- """manage the searching process, start searching from two side"""
- # initial origin node and end node
- origin = Node(coordinate=start, H=hcost(start, end))
- goal = Node(coordinate=end, H=hcost(end, start))
- # list for searching from origin to goal
- origin_open: list = [origin]
- origin_close: list = []
- # list for searching from goal to origin
- goal_open = [goal]
- goal_close: list = []
- # initial target
- target_goal = end
- # flag = 0 (not blocked) 1 (start point blocked) 2 (end point blocked)
- flag = 0 # init flag
- path = None
- while True:
- # searching from start to end
- origin_open, origin_close = \
- find_path(origin_open, origin_close, target_goal, bound)
- if not origin_open: # no path condition
- flag = 1 # origin node is blocked
- draw_control(origin_close, goal_close, flag, start, end, bound,
- obstacle)
- break
- # update target for searching from end to start
- target_origin = min(origin_open, key=lambda x: x.F).coordinate
-
- # searching from end to start
- goal_open, goal_close = \
- find_path(goal_open, goal_close, target_origin, bound)
- if not goal_open: # no path condition
- flag = 2 # goal is blocked
- draw_control(origin_close, goal_close, flag, start, end, bound,
- obstacle)
- break
- # update target for searching from start to end
- target_goal = min(goal_open, key=lambda x: x.F).coordinate
-
- # continue searching, draw the process
- stop_sign, path = draw_control(origin_close, goal_close, flag, start,
- end, bound, obstacle)
- if stop_sign:
- break
- return path
代码讲解:
原理就是分别在start和end开始做A*寻找,不一样的是,在下一次迭代时,从start来看她的goal就不是最原始的了,而是goal中U集(open集)中代价最小的那个点作为下一次start搜寻的目标点。
同理,从goal方向寻找的就是start中U集(open集)中代价最小的那个点作为下一次end搜寻的目标点。
f(p) = g(p) + w * h(p)
另一种思考方式是Dijsktra的算法仅使用,而贪婪的最佳优先搜索仅使用。权重是一种在这两种算法之间平滑插值的方法,其中权重 0 表示 Dijkstra 算法,权重 ∞ 表示贪婪最佳优先搜索。权重 1.0 介于两个极端之间,给出 A*。加权 A* 介于 A* 和贪婪最佳优先搜索之间
f(p) = g(p) + w(p) * h(p)
可能有很多方法可以改变重量,我的直觉使我相信,最好在路径的起点附近使用较高的权重,而在路径的末尾使用较低的权重。这是因为我认为补偿启发式的权重太低,而且它在路径的开头通常太低,而在路径的末尾附近相当准确。然而,研究表明,我的直觉是错误的。最好在路径尽头附近施加重量。
f(p) = g(p) < (2*w - 1) * h(p) ? g(p) / (2*w - 1) + h(p) : (g(p) + h(p)) / w
f(p) = g(p) < h(p) ? g(p) + h(p) : (g(p) + (2*w - 1) * h(p)) / w}
A* 有一些变体允许在计算初始路径后更改世界。D* 适用于您没有完整信息的情况。如果您没有所有信息,A* 可能会犯错误;D*的贡献在于它可以在不花费太多时间的情况下纠正这些错误。LPA* 适用于成本变化时使用。使用 A*,路径可能会因地图更改而失效;LPA* 可以重用以前的 A* 计算来生成新路径。
但是,D* 和 LPA* 都需要大量空间 — 基本上您运行 A* 并保留其内部信息(集合、路径树、值),然后当地图更改时,D* 或 LPA* 会告诉您是否需要调整路径以考虑地图更改
许多加速 A* 的技术实际上都是为了减少节点的数量。在成本统一的方形网格中,一次查看一个单独的网格空间是一种浪费。一种方法是构建关键点(例如角落)的图形并将其用于寻路。但是,您不想预先计算航点图,请查看跳跃点搜索,这是 A* 的变体,可以在方形网格上向前跳过。当考虑当前节点的子节点是否可能包含在 OPEN 集中时,跳转点搜索会跳到从当前节点可见的远处节点。每个步骤的成本更高,但步骤更少,从而减少了 OPEN 集中的节点数量。请参阅此博客文章有关详细信息,此博客文章一个很好的视觉解释,以及Reddit上的讨论的利弊。
另请参阅矩形对称性缩减,这将分析地图并嵌入到图形本身中。这两种技术都是为方形网格开发的。这是为六边形网格扩展的算法.
波束搜索简单说就是给open_set集一个大小限制 防止一些不必要的扩展
在 IDA* 中,“深度”是值的截止值。当值太大时,甚至不会考虑该节点(即,它不会被添加到 OPEN 集中)。第一次通过你处理的节点很少。每次后续传递,您都会增加访问的节点数。如果你发现路径有所改善,那么你继续增加截止值;否则,您可以停止。
A*算法只在8邻域内搜索,而Theta*算法可以有更多的方向选择。
为了改进路径平滑,我们需要在寻路过程中考虑任意角度的线段长度。θ* 算法这样做。在构建父指针时,如果有指向该节点的视线,它将直接指向祖先,并跳过两者之间的节点。它产生的路径比路径平滑更短。但是,Theta* 不保证最短路径。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。