最近突然想到A*这个启发式搜索,一般是用于求最短路径的,但是感觉对其估价函数还不是很清楚,其实问题也就落在了A*的有效性上面了。
参考:
http://liyanblog.cn/articles/2012/09/19/1348045903617.html
https://en.wikipedia.org/wiki/A*_search_algorithm
回到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)进行更新了,其余的就与上一个结点没啥关系了。