绪论

前一章节,我们介绍了两种求解单源结点到其他所有结点最短路径(单源最短路径问题)的算法。但如果只是需要求解某一个结点到另一个结点的最短路径(或者求解少量的最短路径对),求解出单个结点到其他所有结点的最短路径就显得不那么必要(效率略低),我们需要设计出更适用于求解某一个结点到另一个结点最短路径的算法。

BFS显然是求解某一个结点到另一个结点最短路径的一种算法,这一章节介绍的A*算法则是在静态网络中求解最短路径最有效(?)的直接搜索方法。


Background && Idea

课件里对A*算法的描述除了绪论提到的“解决单个结点到单个结点最短路径问题”,“限定于静态网络”,还有“类似于Dijkstra算法”和“假设的最短路径”。


那什么叫做“类似于Dijkstra算法”呢?在学习Dijkstra算法时,课件上也提出了Dijkstra算法类似于Prim算法的说法。我们在Dijkstra算法的推演过程认为Dijkstra算法从某种意义上可以看作“Bellman-ford算法通过贪心的优化”:Bellman-ford优化的版本SPFA算法在每个阶段对前一个阶段所有发生变化的最短路径进行扩展,Dijkstra算法基于“长度越短的最短路径越接近于实际上的最短路径”这一“经验”每一轮只扩展当前网络长度最短的最短路径,最终通过数学方法证明的结果是Dijkstra算法在权都为非负值的网络中能够解决单源结点的最短路问题。

Prim算法则是基于Cut Property,每次选择当前网络中最短的一条边加入最小生成树森林。

两种算法在求解问题时,都是根据一定的依据(长度越短的最短路径越接近于实际上的最短路径,Cut Property)做出在当前看来是最好的选择,来避免为找最优解要穷尽所有可能而必须耗费的大量时间,在找到局部最优的结果后验证结果同样在整体最优或者讨论局部最优具体在哪些情况下最优。

这两种算法类似的思想我们往往称为贪心思想,A*算法是UCS(代价优先搜索)通过贪心思想的优化,与一般的贪心又略有不同,但思想上是一致的。


Algorithm Description

UCS是与BFS同类的搜索算法:

BFS以宽度作为搜索过程的顺序一层一层向外扩展,每一阶段搜索同一深度的所有节点,然后以该深度的所有结点扩展到下一深度的所有节点。由于在无权图(各边的权值相同)中,该点在搜索树的深度=起始点到该点的路径长度,所以BFS在无权图中可以作为一种寻找最短路径的方法。

UCS以代价作为搜索过程的顺序一层一层向外扩展,每一阶段搜索当前代价最低的结点,然后将该节点相邻的结点加入到优先队列中,由于在有权图中,该点的代价=起点到该店的路径长度,所以UCS在有权图(无权图的效率不如BFS)中可以作为一种寻找最短路径的方法。

我们将BFS结点的深度看作UCS结点的代价,可以将BFS看作一种特殊情况的UCS(UCS使用优先队列而BFS使用队列的原因是BFS某一深度的结点扩展到下一深度的结点,扩展出来结点的深度一定是紧随着被扩展出来结点的深度,UCS的扩展过程就不一定,所以需要优先队列作为容器时刻排序)。

A*算法是UCS(代价优先搜索)通过贪心思想的优化。我们常规的UCS过程以代价作为搜索过程的顺序,从最小的代价(起点的代价默认为0)一直按代价的大小顺序搜索到我们需要的结点的代价(或者我们需要的代价的结点),和Dijkstra算法从Bellman-ford算法推演的过程同样,我们在扩展的过程中又会总结出一些“聪明办法”:

假设我们现在想要以最短的距离乘坐火车从广州到达北京,但是我们从广州到北京没有直达车,需要我们从广州先到别的地方去转站,广州可以到达转站的地方有海南和上海,在不知道海南和上海到北京路径的具体情况,我们更倾向于到上海转站,因为从地图上来看上海更接近北京。当然我们不排除到达上海之后发现上海也没直达北京的车,还要转回广州甚至说海南。

对于一类任务,我们很难根据某个阶段得到对于当前阶段最优的方案,或者这样得到的局部最优方案与实际最优方案差异很大,但是任务的最终目标固定,我们能够通过任务进行到某个阶段实际产生的代价和反映当前阶段到目标阶段的数值之和来确定往哪个方向的扩展更优,来避免搜索一些显然为错的状态。

A*算法与Dijkstra算法的对比(实际上与UCS的对比也是一样)如下:

很多地方称这里应该是预期代价,实际上预期代价只是这个值常用的一类,与当前阶段到目标阶段的实际代价相比能够反映A*算法的准确率和效率。也有很多情况的值虽然与预期代价的含义相差很远,但也能够确实地反映出不同阶段的差异,求这个值的函数我们一般称为启发函数,求值之和的函数称为估价函数。

下面的w即为估价函数,d为实际距离,h为启发函数,第一个Kamnik为初始状态,第二个Kamnik为当前状态,Bohimj为目标状态。


A*算法以估价函数的值作为搜索过程顺序的依据,在每次扩展时更新结点估价函数的值,算法进行的流程如下:


Admissible Heuristics

和前面的算法不同,A*算法进行的具体情况还建立在启发函数的情况,启发函数的不同选择也影响A*算法的运行情况。

课件上也没有关于启发函数选择原因的证明,只介绍了怎么选择,启发函数的选择对算法的运行过程有以下影响:

1.启发函数的值小于等于当前状态到目标状态的实际值时,A*算法寻找到的一定是最优方案,此时我们称其为可以“接受的启发法”(Admissible Heuristics)。

2.启发函数的值大于等于当前状态到目标状态的实际值时,A*算法在一些极端情况下会出错,此时我们称其为“不可接受的启发法”。

3.启发函数的值小于等于当前状态到目标状态的实际值时,启发函数的值越接近当前状态到目标状态的实际值,A*算法的效率越高;启发函数的值大于等于当前状态到目标状态的实际值时,启发函数的值越接近当前状态到目标状态的实际值,A*算法出错的概率越低。

第三条给了我们更多样的选择,我们往往可以牺牲掉一定的正确率来换取更高的效率,“是否能够接受”视情况而定。


Example:The N Puzzle

就是N数码问题:给定N个格子的方格图,其中N-1个方格中包含1~N-1的数字,剩下一个方格为空格。


每次允许将一个包含数字的方格内的数字移动到空位的方格。


给定两个状态,求解其中一个状态到另一个状态变换的最少步骤数。

我们将n-1个数字的不同方位看作一个状态,那么这个问题可以转化为求解一个节点到另一个结点的最短路径问题。


求解单个结点到单个结点的最短路径问题最适用的算法是A*算法,我们需要设计一个合理的启发函数来反映某个状态到目标状态还需要进行的步骤数。课件上提出了三种常见的启发函数:离散距离(discrete distance),hamming距离(Hamming distance)和曼哈顿距离(Manhattan distance)。

离散距离:当前状态是否是目标状态,是则为0,否则为1。

hamming距离:当前状态与目标状态位置不相同的数字的个数。

曼哈顿距离:曼哈顿距离这个名词一般在几何度量空间的几何学问题中用的更多,指的是两个点在标准坐标系上的绝对轴距总和。这里的曼哈顿距离指的是,将方格图看作标准平面直角坐标系,当前状态的数字到目标状态对应数字的曼哈顿距离之和。

很显然三个距离的值逐个增大且都小于等于实际的步骤数(原因不作说明,实在不行自己用反证法想想),前两个距离能做到优化非常优先,第三个距离能做到优化是比较明显的。


Backtracking

Backtracking就是回溯的意思,回溯是对DFS的优化,与前面介绍的几种算法的思想并不相同。

从字面意思上来看回溯是查找到某一个阶段无法向下继续查找后回到查找过程中前面的位置选择另外的分支,可是DFS不就是按照这样的原则进行的么?

事实上回溯是希望我们在进行DFS的过程中即使还没有到无法向下查找的状态,但是能够提前预估到从这个状态继续向下查找无法搜索到想要的结果(或者无法得到最优的结果),然后避免掉向下无用的搜索提前回退到上个状态选择别的分支。

从搜索树的角度来看,回溯法带来的效果就像将树的分支剪掉了一段,所以我们一般称它为回溯剪枝(A*对搜索树的变化也是剪枝)。

至于为什么和DFS一样只回退到上一层的状态但单独称它为回溯法,我的理解是回溯法相当于预算出了这条分支某个叶子节点上的最优(差)结果(或者是结果的范围),然后选择向下搜索或者回退到前一个状态,这就相当于你采取最优(差)的策略到达一个叶子节点然后从该叶子结点一下子回到了前面很多层的状态。

有趣一点说,如果一个人的计算能力非常之强或者说对于一件事的认知完全明确(神)。我们想要完成这件事,他能够预算到我们在想要完成这件事所进行的每一步在未来的最好结果和最坏结果,然后决定我们一定要去做某件事或者一定不要去做某件事(当然他并不能回到过去hhhh),那我们会不会觉得他是穿越过来的(纯当乐子的比方,看着玩玩就好了hhhh)?

至于搜索完目标状态之上所有的状态空间和只想要搜索到目标状态无所谓是否是最优的搜索方案的差异是BFS和DFS的差异与回溯法的关系不大(回溯法只是让我们在一条失败分支的搜索过程中提前退出,这是BFS和DFS的本质差距)。

回溯法的经典例子就是:数独问题,N皇后问题,骑士旅游世界问题,走迷宫问题。

课件上对后三个问题只做了问题的介绍,就我个人理解而言迷宫问题和N皇后问题都不能完全作为回溯法的例子,尤其N皇后问题的实现方式几乎就是普通的DFS(到了某个状态确定无法得到一种填充的方式和到了某个状态无法向下搜索是一样的)。


Sudoku

数独问题(相信大家都玩过),课件上提供了较为详细的实现代码如下:



回溯的部分是每填充一个数字判断是否有空余的格子无法填充,如果存在这样的格子就直接回退到前面的状态,来避免对其他格子的填充(搜索树和代码是不一致的hhhh,勉强算它是吧)。


总结

A*算法作为UCS的优化是求解单个结点到单个节点最短路径最有效的方法,在思想上和Dijkstra算法对Bellman-ford算法的优化非常类似,区别就在于A*使用的情况取决于启发函数的设计,并不是像Dijkstra算法一样做当前情况的最优选择,而是依赖于整个问题(包括起始状态,当前状态和目标状态)得到的启发式信息做最优选择。所以虽然两者的思想感觉类似,但Dijkstra算法一般归类于贪心算法,A*算法归类于启发式算法(有看过解答认为启发式算法是效率和准确率的折中,也看过解答认为贪心采用的是贪心启发式)。

(不过Dijkstra算法在所有带权图的情况中的表现和A*算法一样都可以看作近似算法)

回溯法是对DFS的优化,在搜索树的表现上和A*对UCS的优化一样都做到剪枝的效果,不过回溯法的剪枝往往比较难以进行,很多问题的解决并没有采取回溯剪枝就被认为是回溯法了。

让我想想这是第几次写A*算法了emmmm(估计有十几次了),这一次写在算法思想的收获上已经很少了,实现倒是略有所收获。

Lecture 22相关推荐

  1. MIT | 数据分析、信号处理和机器学习中的矩阵方法 笔记系列 Lecture 6 Singular Value Decomposition (SVD)

    本系列为MIT Gilbert Strang教授的"数据分析.信号处理和机器学习中的矩阵方法"的学习笔记. Gilbert Strang & Sarah Hansen | ...

  2. 医咖会stata 笔记(自己能看懂版

    感谢brain 老师和 所有跟制作教程有关 评论区热心解答问题 的人 results:输入的代码+结果  如果运行出错,也会显示 Command:输入代码 regrets y x 课程之后会用do f ...

  3. 最小割与最大流(mincut amp; maxflow)

    这里先介绍mincut和maxflow,为介绍Grabcut打下基础.Grabcut可以用在图像分割和文字二值化中. 1首先介绍Mincut问题. 这部分内容主要翻译自[1],可以看原版理解的更深.由 ...

  4. 最小割与最大流(mincut maxflow)

    这里先介绍mincut和maxflow,为介绍Grabcut打下基础.Grabcut可以用在图像分割和文字二值化中. 1 首先介绍Mincut问题. 这部分内容主要翻译自[1],可以看原版理解的更深. ...

  5. 地球,再一次完成了绝妙的自转 ......

    在这凌晨三点五十七的春夜 地球仍然在自转 哦,别忘了! 地球还环绕这太阳公转呢 对了,还有-- 地球还有他的可爱的小情人--月亮妹妹 这个不离不弃的小可爱 也绕着地球转了亿万年了 她是地球的卫星 守卫 ...

  6. Java代码可理解性/可读性及编码规范

    目录 目录 0.写在前面 1.可理解性的标准(alias:可读性) 1.1.Code quality measurement:WTFs/min 1.2.Metrics 1.3.How to do in ...

  7. [计算机图形学]动画与模拟:欧拉方法、刚体与流体(前瞻预习/复习回顾)

    一.前言 这是本专栏的倒数第二篇文章了,为什么不是最后一篇?因为我要单独写一篇总结哈哈,不管怎么说,从今年的3.13的MVP变换开始写,写到现在,也是一个很大的工程了,我很高兴能在大二下学期的期中这个 ...

  8. 如何获取物体表面的法向量?好好谈谈光度立体法

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本文转自:AI算法与图像处理 这种逼真的效果,一个很重要的原因是获 ...

  9. MIT18.065 数据分析、信号处理和机器学习中的矩阵方法-学习笔记

    文章目录 MIT18.065 数据分析.信号处理和机器学习中的矩阵方法 Lecture 1 The Column Space of A Contains All Vectors Ax A=CR A=C ...

最新文章

  1. 巧用CSS的 Mask 滤镜
  2. 计算机视觉实习岗面试准备(二.深度学习)
  3. Comparator 与 Comparable
  4. 矩阵乘法递推的优化艺术
  5. 【JSP】web.xml配置JavaWeb项目首页
  6. 红橙Darren视频笔记 类加载机制(API28) 自己写个热修复 查看源码网站
  7. 通过命令行工具使用阿里云资源编排服务
  8. Java 正则表达式的用法与实例
  9. 微信公众号推送模板信息
  10. 悼念前端大牛司徒正美
  11. c语言10h,bios 10h中断是什么意思啊?
  12. OpenGL 简化点光源与平行光的对比实验
  13. 案例: 模拟京东快递单号查询
  14. potentially fixable with the `--fix` option.
  15. 大数据学习之一——Hadoop单机部署
  16. 主页被改为www.n220.com www.129yy.cn
  17. Linux高可用之heartbeat
  18. Mybatis从入门到精通上篇
  19. STM32物联网通讯GPRS
  20. 【纪念篇】AS最初的kotlin-android-extensions插件走远了

热门文章

  1. 科学史 科学的旅程 雷.斯潘根贝格 读书笔记要点备忘
  2. Kotlin骚气写法 三
  3. 程序人生 - 数字化人民币的无网络支付是如何实现的?
  4. 【微信小程序】全局分享和页面分享
  5. 国内五款好用的开源建站系统
  6. ZigBee的发展也有“碎片化”zigbee模块
  7. 纯CSS写个绿荫足球场,为世界杯喝彩
  8. 为XV6系统扩展一个系统调用需要修改的文件
  9. C语言字符串输入及输出的常用格式
  10. 开源的调色板软件:焰火十二卷(Rickrack)