算法入门到进阶(三)——搜索技术(BFS和A*算法)

文章目录

  • 用BFS求最短路径
  • A*算法与最短路径
  • A*算法与八数码问题
  • 双向广搜
    • 题目
    • 思路


用BFS求最短路径

最短路径是图论的一个基本问题,有很多复杂的算法。不过,在特殊的地图中,BFS也是很好的最短路径算法。下面仍然以之前讲的“红黑瓷砖”为例进行分析,任务是求两点之间的最短路径。
如下图所示,黑点表示可以走的路,#表示不能走,求起点@到所有黑点的最短距离
算法入门到进阶(三)——搜索技术(BFS和A*算法)_第1张图片方法很简单,从@出发用BFS搜索所有点,记录到达每个点时经过的步数,即可得到从@到所有黑点的最短距离,图c给出了答案。
在这个例子中,BFS搜最短路径的计算复杂度是O(V+E),非常好。
这个例子很特殊,图是方格形的,相邻两点之间的距离相同。也就是说,绕路肯定更远,BFS先扩展到的路径,肯定就是最短的。
如果相邻的距离不同,绕路就可能更近,BFS就不适用了。关于最短路径的通用算法后面会详细介绍。
下面是A*算法和BFS的优化

A*算法与最短路径

BFS是一种“盲目的”搜索技术,它在搜索的过程中并不理会目标在哪里,只顾自己乱走,当然最后总会走到终点。
稍微改变上面的方格图,如下,现在的任务是求起点@到终点t的最短路径。
算法入门到进阶(三)——搜索技术(BFS和A*算法)_第2张图片
如果仍用BFS求解,程序会搜索所有的点,直到遇到t点。不过,如果让一个人走这个图他会一眼看出向右上方走可以更快地到达t地最短路径。人有“智能”,那么能否把这种智能教给程序呢?这就是“启发式”搜索算法。启发式搜索算法有很多种,A算法是其中比较简单的一种。
简单地说,A
算法是“BFS+贪心”,有关贪心算法地解释,后面博客会介绍。(这里给大家推荐一篇博客,这个网页用动画演示了BFS,A*,Dijkstra算法的原理。
推荐网页-算法原理

在图a中,程序如何知道向右上方走能更快到达t?这里引入曼哈顿距离是指两个点在标准坐标系上的实际距离,在上图中@的坐标和t的坐标在横向和纵向的距离之和,它也被形象地称为“出租车距离”。
图b是从起点开始的第一轮BFS搜索,邻居点上标注的数字3是这个点到终点t的曼哈顿距离。图c是第2轮搜索,标注2的点是离终点更近的点,从这些点继续搜索;标注4和5的点距离终点远,先暂时停止搜索。经过多轮搜索,最后到达了终点t,如图d所示。

在这个过程中,图中很多“不好的”点并不需要搜索到,从而优化了搜索过程。
上面的图例比较简单,如果起点和终点之间有很多的障碍,搜索范围也会沿着障碍兜圈子,之后才能到达终点,不过,仍然有很多点不需要搜索。以下面的这幅图为例,进行分析
算法入门到进阶(三)——搜索技术(BFS和A*算法)_第3张图片
A是起点,B是终点,黑色方块是障碍,浅色阴影方块是用曼哈顿距离进行启发式搜索所经过的部分,其他无色方块是不需要搜索的。搜索结束后,得到一条最短路径,如上图的虚线。
这个方法就是A算法,下面给出他的一般性描述。
在搜索过程中,用一个评估函数对当前情况进行评估,得到最好的状态,从这个状态继续搜索,直到目标。设x是当前所在状态,f(x)是对x的评估函数,有:
f(x)=g(x)+h(x)
g(x)表示从初始状态到x的实际代价,它不体现x和终点的关系。
h(x)表示x到终点的最优路径的评估,它就是“启发式”信息,把h(x)称为启发函数。很显然,h(x)决定了A
的算法优劣。
特别需要注意的是:h(x)不能漏掉最优解。
在上面的例子中,曼哈顿距离就是启发函数h(x)。曼哈顿距离是一种简单而且常用的启发函数。
在上面这个例子中,可以看出A*算法包含了BFS和贪心算法。

  1. 如果h(x)=0,有f(x)=g(x),就是普通的BFS算法,会访问大量的方块。
  2. 如果g(x)=0,有f(x)=h(x),就是贪心算法,此时上图标注的“*”方块也会被访问到。贪心法的缺点是可能陷在局部最优中,例如陷在“ * ”的方块中,被堵在障碍后面,无法到达终点。

A*算法与八数码问题

八数码问题也可以用A*算法进行优化。通常考虑3种评估函数:

  1. 以不在目标位置的数码的个数作为评估函数
  2. 以不在目标位置的数码与目标位置的曼哈顿距离作为估价函数。
  3. 以逆序数作为评估函数(逆序数可以判断八数码是否有解)

双向广搜

双向广搜是BFS的增强版。
前面提到,可以把BFS想象成在一个平静的池塘丢一块石头,激起的波浪一层层扩散到整个空间,直接到达目标,就得到了从起点到目标点的最优路径。那么,如果同时在起点和目标点向对方做BFS,两个石头激起的波浪向对方扩散,将在中间的某个位置遇到,此时,即得到了最优路径。在绝大多数情况下,双向广搜比只做一次BFS搜索的空间要少很多,从而更有效率。
从上面的描述可知,双向广搜的应用场合是知道起点和终点,并且正向和逆向都能进行搜索。
下面是一个典型的双向广搜问题

题目

有一个8x8的棋盘,上面有4个棋子,棋子可以上下左右移动。给定一个初始状态和一个目标状态
,问能否在8步之内到达

思路

题目确定了起点和终点,十分适合双向BFS。要求在8步之内到达,可以从起点和终点分别开始,各自广搜4步,如果出现交点则说明可达。
程序比较繁琐,也有很多细节,有兴趣的同学可以尝试练习此题。

你可能感兴趣的:(算法入门到进阶,算法,宽度优先,图论)