单源最短路
顾名思义就是寻找一个源点到其它的点的最短路,暴力的dfs或者bfs就不说了,下面讲讲几种单源最短路的算法。
- SPFA(shortest path fast algorithm)
这个算法的实质就是利用bfs,我们先将源点到源点的距离设置为0,到其它的距离设置为无穷大(一般0x7fffffff),然后将源点加入队列,用队首的点去bfs,更新它能到达且能更新的的点,然后将未进入队列的点加入队列以备后续更新使用,然后将已经出队的点标记消掉,不断这样进行这个操作(这个也就是松弛操作),最后无法再更新任何一个点时,队列为空,最短路也就找完了,理论复杂度为O(kn)O(kn),kk为进队次数,一般k≤k≤常数。
这个算法在一般的图和随机图上面运行效果良好,但是在一些精心构造的图上面就会卡到复杂度上限O(nm)O(nm)(每个点进队m次)。
下面介绍另一种算法。
- Dijistra
这个算法同样是用bfs,每次找到距离源点最近的且未被用过的点,然后拿它去更新其它点,而这个点以后再也不会被更新到(除非有负环,那么普通的Dijistra就无法使用),这样每个点只会用来更新一次其它点,每次寻找最近的点暴力复杂度为O(n)O(n),然后更新的复杂度为它的度数(一般看作常数,除非菊花图),所以复杂度总的来说为O(n2)O(n2)。
- Dijistra+堆优化
我们发现上述的算法中,有一个寻找最近点的O(n)O(n),可以拿一个数据结构维护,将O(n)O(n)降到O(logn)O(logn),那么维护最小值我们可以简单的使用堆(自己手打或者STL的优先队列),那么该算法就被优化到了O(nlogn)O(nlogn),虽然一般图和随机图跑的没有SFPA快,但是在精心构造的图上面,它复杂度的优秀性就体现出来了。(NOI2018的day1T1可以说明)
多源最短路
多源最短路,就是求图上的每一个点到其它点的最短距离,朴素简单的想法就是跑nn遍单源最短路算法,但是这里还有其它的算法可以解决这个问题。
- Floyd
这个算法实质上是利用了动态规划,DP的思想,我们定义如下状态f[i][j]f[i][j],表示i⇒ji⇒j的最短路长度,然后我们枚举一个中转点kk,用它去不断更新其它情况,转移方程为f[i][j]=min(f[i][j],f[i][k]+f[k][j])f[i][j]=min(f[i][j],f[i][k]+f[k][j])。这样n3n3就可以求出多源最短路。(其实似乎跑nn边Dijistra+堆优化好像才O(n2logn)O(n2logn)的复杂度,不过Floyd的常数明显较小)。
这个算法还有个用途,其实从它的转移上都可以看出,我们可以求必须经过某个点的多源最短路,这时就不用枚举中转点,而是已知中转点,然后去更新答案,复杂度为O(n2)O(n2)。
次短路算法
A-star(A*)启发式搜索算法,原理是dfs时利用一个估计函数来剪枝。
后面待更新完善……