谈谈A*

最近突然想到A*这个启发式搜索,一般是用于求最短路径的,但是感觉对其估价函数还不是很清楚,其实问题也就落在了A*的有效性上面了。

参考:

http://liyanblog.cn/articles/2012/09/19/1348045903617.html

https://en.wikipedia.org/wiki/A*_search_algorithm

http://baike.baidu.com/link?url=UCU0dU7DIkhKx111EQcB2DZf28Z3do3JbEQfM-l-N8hfVaApT7RUGgVo93tIN-lQtovCst0TysYGG0rd-P2KhK

回到A*上面,其实看A*第一眼,就会感觉就是一个BFS,就是在BFS的基础上加了一个估价函数了,而这个估价函数就是A*的关键所在,因为A*并不像BFS一顿狂搜,它通过这个估价函数来指导下一次搜索应该走哪个节点,哪条路径。这样的好处就是在大规模的搜索中,BFS的时间复杂度肯定是让人受不了的,而这时A*就能够派上用场了。

所以对A*就出现了两个问题了:

1. 究竟什么是估价函数

2. 估价函数怎么求

1. 估价函数

其实估价函数还是比较直观,也没怎么绕。
定义估价函数f(x) = g(x) + h(x)

假设现在是要求A到B的路径:
g(x): 表示从A到x的消耗,实际消耗。
h(x): 表示x到B的消耗,估计消耗。当选取的是实际的最小消耗的时效率最高了,而在现在一般K短路中就是先用SPFA等最短路算法求一下逆向最短路,然后把这个作为h(x)进行下一步的K短路的求解了。

需要注意的是:其实这里的消耗并不就是最短消耗或者实际消耗之类的,而是编程者给定的一个估计消耗。这里选取的计算方式将会影响最终搜索的效率和正确与否,因此一般来说这里消耗的选取与实际的消耗如果是正相关的话,应该就能够保证正确了。(个人看法,后面会有严格证明)

对于估价函数这里,又会有两个问题:时耗 和 正确性。

具体的时耗计算肯定是与估价函数有关了,所以也会有一些情况考虑,这里就不多扯了,直接考虑下最差的时耗,那就是相当于估价函数没有作用了,就是普通的BFS的消耗了。

正确性:究竟怎么选取估价函数就是正确的,或者说是随意选取呢?

首先可以考虑一种极限情况,假设我们选取的h(x)就是实际的最短路的话,我们可以发现,估价函数 f(x) = g(x) + h(x)其实就是A通过x到达B的实际最短消耗,那么我们选取一个最小的估价值,就走那一个就能够保证是正确的了。

因为g(x)其实是实际计算得出的消耗,因此这个我们并不是人为随意定的,可以先不考虑,这时候我们就需要关注下h(x)的选取了。

百度百科上面有一个说法:

估价值h(x)<= x到目标节点的实际消耗,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。
并且如果h(x)=d(x),即距离估计h(x)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。

如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。

首先不考虑这种说法到底是正确与否,单纯从这些条件去证明就比较困难了,因为实际消耗到底是什么我们是不知道的,这就比较难说明这个是正确的了。

而Wiki上面有一个证明(图片来在Wiki):

这就很严谨了,这里是 求 f到g的最短路。

假设条件满足: h( x ) <= d( x, y ) + h( y ),其中d(x, y)表示的是从任意x到其相邻节点(就是有连接的节点)y的距离,而h(x)的含义还是前面的从x到终点g的估计路径了。

而上图的推导就比较明显了,可以看成是从f出发了,然后就按照一条一条路径走到最后的节点g了,也就是搜索的过程,这里是假设L(P)是经过中途若干个点的最短路径,那么能够保证使用A*所求出来的路径是应该都是小于等于实际的最短路径的,那么这时候A*是一定能够找到最短路的。

这时候我们再回到百度百科上的说法,h(x)<= x到目标节点的实际消耗是能够找到最短路的,其实也是差不多一个意思。

其实我们编程的时候关心的还是究竟应该怎么样选取这个函数,由上面其实已经很明显了,那就是足够小就行,能够保证比实际对应的所有可能距离都小就Ok了,这还是比较容易满足的,但这只是保证正确性,效率这方面还是得仔细选取下。

2. 估价函数更新

直接用当前结点,对其周围可能下一步走到的节点进行更新,主要就是更新f(x) = g(x) + h(x), g(x)是针对于上一结点的g(x)进行更新了,其余的就与上一个结点没啥关系了。

时间: 2024-10-07 05:09:09

谈谈A*的相关文章

谈谈对CAP定理的理解

谈谈对CAP定理的理解 CAP定理的常规解释是任何分布式系统只能在一致性(Consitency),可用性(Availability)和分区容忍性(Partition Tolerance)中三选二.这个解释很让人费解,笔者在看了一些文章后谈谈我对它的理解,还请斧正. 从问题出发 假设我们用一台服务器A对外提供存储服务,为了避免这台服务器宕机导致服务不可用,我们又在另外一台服务器B上运行了同样的存储服务.每次用户在往服务器A写入数据的时候,A都往服务器B上写一份,然后再返回客户端.一切都运行得很好,

谈谈我眼中的安徽企腾信息技术集成有限公司

在这里工作一段时间后,说说自己眼中的安徽企腾,我尽量本着客观的原则,不带任何主观因素与感情色彩. 首先,先说说规模,所谓的分成售前与售后,其实就是虚张声势,售前不过是一些笔记本的售后维修,售后与售前基本上没什么关系.而售后,销售加上技术,最多时也不过7个人.平时一些项目,大一点,一些不能做的直接外包出去,小一点的项目,所谓的"施工队",就是全体总动员. 公司里做了好几块业务,其中一块是飕飕商用路由,刚开始,想的是多么好,但是最后却被浇了一盆冷水,市场根本不接受,唯一做了一家宾馆,还是连

谈谈JS里的{ }大括号和[ ]中括号的用法

谈谈JS里的{ }大括号和[ ]中括号的用法,理解后就可以看懂JSON结构了. 一.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数. 如:var LangShen = {"Name":"Langshen","AGE":"28"}; 上面声明了一个名为"LangShen"的对象,多个属性或函数用,(逗号)隔开,因为是对象的属性, 所以访问时,应该用.(点)来层层访问:LangShe

《谈谈认同》这个文章有点晦涩 写的不太好

认同是一个人主观能动性的一个影响因素.至于人的主观能动性还有什么影响因素,先不讨论,而且我也没学过也没想过.在可选择事物的主观能动性上,认同应该算最基本也是影响最大的了.回到主题,我们来谈谈认同.        认同有三个表现:第一.口头认同.第二.行动认同.第三.心理认同.简单的理解,就是口头认同只说认同,但不做,事前一套事后一套.行动认同就是说也说了,干也干了,但心里不这样想.心理认同就是口手心合一.但我们都清楚认同其实从本质上讲只有一种,就是心理认同.只有心理认同才是真正的认同.但是在工作

谈谈vector容器的三种遍历方法

说明:本文仅供学习交流,转载请标明出处,欢迎转载! vector容器是最简单的顺序容器,其使用方法类似于数组,实际上vector的底层实现就是采用动态数组.在编写程序的过程中,常常会变量容器中的元素,那么如何遍历这些元素呢?本文给出三种遍历方法. 方法一:采用下标遍历 由于vector容器就是对一个动态数组的包装,所以在vector容器的内部,重载了[]运算符,函数原型为:reference operator [] (size_type n);所以我们可以采用类似于数组的方式来访问vector容

谈谈怎么使用JSONP

JSONP是什么,其实它是目前主流的实现跨域通信的解决方案. 因为我们都知道,在我们使用ajax去发起HTTP请求的时候,是不可以跨域的.也就是不能在不同域名下.端口等去请求.如果我们强行这么做的话,它是会报错. 这里举个例子. function createXHR() { var xhr = new XMLHttpRequest(); return xhr; } function ajax(url) { var xhr = createXHR(); xhr.onreadystatechange

你读到了什么:谈谈阅读的空与实

開始写点文字后,有些文章有人留言评论说:「都是些空话,正确的废话」,而有些文章有人又会留言评论说:「就喜欢这种.满满的干货.实在」. 究竟什么是空还是实蛮让我困惑的,思考了一段时间后今天就想谈谈我从阅读文章中究竟读到了些什么? 不管是别人评价是空话还是实在,于写作者我而言仅仅负责将自己思考后的观点清晰的表达,而至于是用「干货」还是「湿货」的形式来表达事实上取决于支撑观点的内容本身. 代入去想我知道评论说文章太空的人本身对阅读的期待是能从中收获实用甚或立马用的上的东西.凡是怀有相似期待的读者多半是

从面试题谈谈js的闭包,原型

最近群里有小伙伴分享了两道面试题,这里我谈谈自己的理解,废话不多说,上第一题: var n = 10; var obj = { n:20, fn:(function(){ this.n += 2; n *= 3; return function(){ this.n *= 2; n += 1; console.log(n) } })(n) } var fn = obj.fn; fn(); obj.fn() console.log(n,obj.n) 这个题目中,定义的obj对象的fn属性是个自执行的

谈谈我对Linux系统学习的历程回顾

众所周知,Windows 和Linux 是目前最流行的2个操作系统.Windows系统适合普通用户,它的优势是图形化界面,简单易用,使用起来门槛很低,很容易上手,所以,windows占有了大多数普通用户群体.而Linux 被誉为黑客的操作系统,因其稳定和命令行操作的高效性而广泛用于开发工作,占有绝大多数开发者群体.当然,关于这两大系统的优缺点,这里就不再赘述,我主要想谈谈我的Linux的学习历程参考书籍<Linux就该这么学>和心得体会. Linux初体验 一年前,我还不知道Linux为何物,

谈谈java创建对象

作为一门面向对象的语言,我们学习java,对于对象的学习非常重要.大多的教程上都用抽象的概念驱使着我们理解对象,把现实抽象为对象.然而忽略对创建对象的研究.如果说学习抽象思维,运用抽象思维虚拟现实是走向java顶端的关键,那创建对象可以说是通向成功的垫脚石吧.今天我们就来谈谈创建对象. 说到创建对象,new 方法是java最常用也是最简单的方式.而恰恰是它的简单,让我们用的那么的随意. 举个例子: public class Demo { private String i; private Str