最短路问题
Dijkstral
利用贪心的思想,不能处理存在负边权的情况
适用条件:每次从堆顶取出的节点可以保证当前节点已经拥有最小权值
结果:可以得到所有点到起点的最短距离
朴素版本:
- 时间复杂度\(O(n^2)\)
- 用邻接矩阵进行存储
- 外层循环n - 1次,每次循环所有结点,找到一个到起点距离最短、不在集合中(st为false)的结点,将这个结点加入到集合中,并根据这个节点更新其它结点的距离
堆优化版:
- 时间复杂度\(O(mlogn)\)
- 用邻接表(链式前向星)进行存储
- 使用
priority_queue<PII,vector<PII>, greater<PII>
,每次队头的就是距离最小的节点 - 使用标记数组st,st为true表示该结点加入过队列,即已经得到了该点到原点的最小值
- 先判断距离最小的结点的st数组是否为true,如果是说明已经得到最小值,就跳过后续步骤;否则,修改st的值为true,并用这个节点更新其他节点,更新的节点加入到队列中\(\color{red}{(先判断st,再判断距离)}\)
Bellman_Ford
每次对所有的边进行松弛操作
- 时间复杂度\(O(mn)\)
- 用结构体进行存储
- 循环k次(边数限制为k),每次利用上一轮的dist数组更新这一轮的dist数组(所以需要拷贝一份)
Spfa
优化版的Bellman_Ford,每次只对上次更新过的点连接的边进行松弛操作
- 宽搜(默认边权全为1)
- 时间复杂度\(O(mn)\)
- 用邻接表(链式前向星)进行存储
- 利用队列,因为边权都为1,所以哪条路先到,哪条就是最短路
- 增强版
- 时间复杂度\(O(mk)\),最坏k等于n
- 用邻接表(链式前向星)进行存储
- 使用队列,加入到队列中表示与该节点相连的边待松弛
- \(\color{red}{每次出队列需要重新设置st数组为false}\)
- \(\color{red}{先判断距离,再判断是否要加入队列(即判断st数组是否为false)}\)
- 利用spfa判断负权回路
- 时间复杂度\(O(n)-O(mn)\)
- 如果存在负环,那么一旦进入这个负环,就会一直循环,因为只要在负环里面dist就会一直减,所以可以计算每个节点距离最短的路上有几个结点,如果大于等于n必定存在负环,因为如果只存在正环或者不存在环,那么最长的应该是n-1;因为负环不一定是从结点1开始的,所以在起始的时候需要把所有结点加入到队列中
Floyd
多源最短路,直接暴力遍历
- 时间复杂度\(O(n^3)\)
- 三层循环遍历,最先遍历k
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 眨眼的小星星!