A*算法寻求最短路
A*算法关键在在于评估函数。评估函数分为两个部分,f(n) = g(n) + h(n):
- 如果g(n) = 0的话,那么我们只关心从当前点到目标的距离,类似贪心扩展
- 如果h(n) 不大于实际距离的话,那么一定可以得到最优解。h(n)越准确那么效率越高。
- 如果h(n) = 0的话,那么退化成为单源最短路静问题,dijkstra算法。
对于迷宫函数使用曼哈顿距离是最简单也是安全的,但是相比BFS可以少访问不少节点。
def astar(maze, src, dst):
def get_est_dist(p, to_src_dst):
to_dst_dist = abs(p[0] - dst[0]) + abs(p[1] - dst[1])
return to_dst_dist + to_src_dst
nexts = []
item = (get_est_dist(src, 0), src, 0)
heapq.heappush(nexts, item)
visited = set()
visited.add(src)
dist = -1
while nexts:
(est_dist, p, d) = heapq.heappop(nexts)
if p == dst:
dist = d
break
for u in nns(maze, p):
if maze[u[0]][u[1]] == 1 and u not in visited:
visited.add(u)
item = (get_est_dist(u, d + 1), u, d + 1)
heapq.heappush(nexts, item)
print('astar: visited {} nodes, dist: {}'.format(len(visited), dist))
return dist
突然发现python里面允许比较tuple是一件非常有意义的事情:将tuple[0]设置成为比较value的话, 那么就可以直接将tuple作为数据放在最小堆里面,而不用单独定义类型和编写比较函数。
我的测试用例里面生成了一个200x200的迷宫图,可以看到astar访问的节点数量是BFS的一半。
find shortest path: (0, 0) -> (199, 199) bfs: visited 31023 nodes, dist: 398 astar: visited 16973 nodes, dist: 398