3 A*算法实现8数码问题

  • 3.1算法介绍
  • 3.2实验代码
  • 3.3实验结果
  • 3.4实验总结

3.1算法介绍

Astar算法是一种求解最短路径最有效的直接搜索方法,也是许多其他问题的常用启发式算法。它的启发函数为f(n)=g(n)+h(n),其中,f(n) 是从初始状态经由状态n到目标状态的代价估计,g(n) 是在状态空间中从初始状态到状态n的实际代价,h(n) 是从状态n到目标状态的最佳路径的估计代价。

h(n)是启发函数中很重要的一项,它是对当前状态到目标状态的最小代价h*(n)的一种估计,且需要满足

h(n)<=h*(n)

也就是说h(n)是h*(n)的下界,这一要求保证了Astar算法能够找到最优解。这一点很容易想清楚,因为满足了这一条件后,启发函数的值总是小于等于最优解的代价值,也就是说寻找过程是在朝着一个可能是最优解的方向或者是比最优解更小的方向移动,如果启发函数值恰好等于实际最优解代价值,那么搜索算法在一直尝试逼近最优解的过程中会找到最优解;如果启发函数值比最优解的代价要低,虽然无法达到,但是因为方向一致,会在搜索过程中发现最优解。

h是由我们自己设计的,h函数设计的好坏决定了Astar算法的效率。h值越大,算法运行越快。但是在设计评估函数时,需要注意一个很重要的性质:评估函数的值一定要小于等于实际当前状态到目标状态的代价。否则虽然程序运行速度加快,但是可能在搜索过程中漏掉了最优解。相对的,只要评估函数的值小于等于实际当前状态到目标状态的代价,就一定能找到最优解。所以,在这个问题中我们可以将评估函数设定为1-8八数字当前位置到目标位置的曼哈顿距离之和。

Astar算法与BFS算法的不同之处在于每次会根据启发函数的值来进行排序,每次先出队的是启发函数值最小的状态。

Astar算法可以被认为是Dijkstra算法的扩展。Dijkstra算法在搜索最短距离时是已知了各个节点之间的距离,而对于Astar而言,这个已知的距离被启发函数值替换。

3.2实验完整源代码

下载链接:

3.3实验结果

仍然用相同的例子,用Astar进行搜索。

python 实现八数码问题 八数码问题a*算法python_算法

将找出的解从初始状态一步一步输出到解状态。

python 实现八数码问题 八数码问题a*算法python_python 实现八数码问题_02

从结果中可以看出总共进行了9次遍历,并在第4层时找到了解状态。

下面我们来看一看Astar的所有9次遍历,以此来更深入的理解Astar的原理。稍微对代码进行改动,使其输出遍历次数和当前状态的启发信息(其中F是启发值,G是当前深度,H是不在位棋子的曼哈顿距离之和)。由于结果太长,为了方便展示,下面将以树的形式展示。

python 实现八数码问题 八数码问题a*算法python_人工智能_03

上面输出的解就是按照红色路线标注找到的,从遍历次数和相应状态的启发信息可以看出每次对启发函数值最小的状态进行扩展,依次进行搜索。

3.4实验总结

从三个算法的遍历次数可以看出Astar算法更加优秀,能够更快的找到解。但是因为上面给出的八数码题目太简单了,只需要4步就能解决问题,所以看起来优势没有那么明显。下面我们选择另一个比较难的,需要更多移动步数的题目,以此来体现启发式搜索相较于盲目搜索的优越性。用三种算法搜索下面八数码的解。

python 实现八数码问题 八数码问题a*算法python_算法_04

下面是比较的结果

python 实现八数码问题 八数码问题a*算法python_人工智能_05

python 实现八数码问题 八数码问题a*算法python_python 实现八数码问题_06

python 实现八数码问题 八数码问题a*算法python_python 实现八数码问题_07

显。下面我们选择另一个比较难的,需要更多移动步数的题目,以此来体现启发式搜索相较于盲目搜索的优越性。用三种算法搜索下面八数码的解。

可以看出来Astar在一百次遍历之内就找到了解,而另外两个盲目搜索算法则需要几千次才搜索到。