A*算法寻求最短路

Wikipedia code on github

A*算法关键在在于评估函数。评估函数分为两个部分,f(n) = g(n) + h(n):

对于迷宫函数使用曼哈顿距离是最简单也是安全的,但是相比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