1 什么是A*算法
假设一个走迷宫游戏,我将 A 点定义成起点也就是开始状态,定义 B 为终点也就是结束状态。我们的目标就是找到从 A 走到 B 地最佳路径,如下图所示:

我们可以将上述的迷宫看做一张图,在简单的情况下(比如这个),生成的图由少量节点和边组成,BFS、DFS 和 Dijkstra 就足够了。然而,在现实生活中,因为我们通常要处理组合复杂性非常大的问题,我们将不得不处理大量的节点和边,而 BFS、DFS 和 Dijkstra 要不可避免地遍历整张图,搜索代价十分巨大。因此,我们必须使用某种意义上的引导算法(启发式算法)。A 算法就是一种启发式算法。与其他图遍历算法不同,A 仅根据其功能在看起来有希望且合理的情况下执行一个步骤。它朝着目标前进,不考虑任何非最佳步骤,所以 A 所搜索出来的路径一定是最优路径。这使得 A 对于人工智能系统非常有用——尤其是在机器学习和游戏开发中,因为这些系统复制了现实世界的场景。
1.1 A* 的基本概念
  A 基于使用 启发式 方法来实现最优性和完整性,是最佳优先算法的一种变体。当搜索算法具有最优性时,这意味着它可以保证找到可能的最佳解决方案。当搜索算法具有完备性时,这意味着如果给定问题的解决方案存在,则该算法保证找到它。
  每次 A 进入一个状态即图中的一个节点,它计算从当前节点移动到所有相邻节点的成本 f(n) ,然后进入具有最低   f(n) 的节点,注意 n 指的是当前节点的邻居节点。计算公式如下:
其中:
f(n):从初始状态经由状态n到目标状态的代价估计;g(n):在状态空间中从初始状态到当前状态n的实际代价;h(n):从当前状态n到目标状态的最佳路径的估计代价。
为了能够重建任何路径,我们需要用具有最佳 f(n) 值的相对标记每个节点。这也意味着如果我们重新访问某些节点,我们也必须更新它们的最佳邻居。A* 的效率高度依赖于启发式值h(n),并且根据问题的类型,我们可能需要使用不同的启发式函数来找到最佳解决方案。。
1.2 启发函数的可接受性和一致性
  如果一个给定的启发式函数从不高估 n 和目标节点之间的实际距离,则 h(n) 是可接受的。因此,对于每个节点 n,适用以下公式:
h*(n) 是 n 和目标节点之间的实际距离。但是,如果函数确实高估了实际距离,但从不超过 d,我们可以肯定地说,该函数产生的解的精度为 d(即它不会高估从开始到结束的最短路径超过 d)。
  如果估计总是小于或等于目标节点 n 和其任何邻居之间的估计距离,加上到达该邻居的估计成本,则给定启发式函数h(n) 是一致的:
如果 h(n) 是一致的,那么我们就知道到任何已经检查过的节点的最佳路径。这意味着这个函数是最优的。
2 Python 实现 A* 算法
本次实现从零开始,也即先构建一个加权有向图,其次利用 A* 算法寻找图中的某一节点到达另一节点的的最佳路径,其中:
- 图的存储结构是邻接列表,可参考:Python 中的图:图的存储结构;
 - 为了方便,本次定义的启发函数 
h(n) = 1,即任何的当前节点到目标节点的最佳路径的估计代价均为1。 
图的构建如下:
1  | adjacency_list = {'A' : [('B', 1), ('C', 3), ('D', 7)],  | 
代码如下:
1  | adjacency_list = {'A' : [('B', 1), ('C', 3), ('D', 7)],  | 
代码中有详细注释,便不再讲解。效果如下: