搜索的瓶颈就是搜索的时间复杂度和空间复杂度。所以有的时候要采取必要的剪枝策略。而剪枝策略中将充满着玄学。
这篇文章主要总结一下A*的思维来解决第k短路问题。
什么是A*算法?
A*详细介绍
前辈们已经说的很清楚了。构造了一个如下的函数:
\(f(x) = g(x)+h(x)\)
g(x)为实际搜索的答案,h(x)为一个启发的因子。
我们一般用的BFS其实就是一种最坏情况的A*算法,\(h(x) = 0;\)
这个函数有很多的应用的背景:比如求最短路的时候,我们搜索到一个状态的时候,然后加上最好的曼哈顿距离(h(x)),这时候的值比已经找到的值要大。那么我们完全没有必要接着往下找最短路了。这样的方案是不可能为最优方案的。
问题
题意
- 首先给定n, m:n表示节点的个数,m代表有向图的边。
- 下面的m行给定从节点u到v的距离dist
- 最后一行给定起点(s), 终点(t), 第k短路
- 若s == t,必须在外面经过一些点再返回。
题解
- 暴力搜索没想好怎么暴力搜索。如果能暴力,时间复杂度也是不行吧。
- 我们先预处理出来图中所有的点到terminal的最短路,这个来作为h[]函数(启发函数)。
- 而我们下面要讨论的第k短路问题,是一个不断将可能的解放入优先队列(pq)的过程之中。这些解可能不是最优的,但是由于优先队列的性质,我们取出来的一个是当前最优的结果。
- 当terminal节点被取出来k次之后,说明这就是第k短路的结果了。
更多的理解和说明
A*其实就是给BFS()的时候加了一个h()函数,h()函数设计的好坏影响着整个的算法的优劣程度。好的h()函数可以极大的介绍搜索的空间。
而且求第k短路的时候看到了一句醍醐灌顶的话:
优先队列相当于把所有的情况都先保存起来,这些解不一定是最优的。不管是骡子还是马,都放进优先队列中。然后从最优的解(队首)开始向外拓展。最后找到第k优的解。
AC代码
其实前面的原理没看懂也没什么,结合下下面的代码,先把terminal当成起始点跑dijkstra,然后用A*算法来枚举所有的可能的解就可以了。
|
|
k短路更新
我原来的k短路太慢了。。。
poj上面dij其实是要比这个快的,但是今天没有卡spfa
题目链接
ac code
|
|
参考博客
the kth shortest path
kth shortest path②