在要咕的边缘疯狂试探是时候补齐自己的图论知识了——Dijkstra算法和Floyd算法
首先这是一个对于无负权边的图的一个判别方法,如果有负权边那么就要使用另一个算法叫SPFA算法(先不深究)
Dijkstra算法
Dijlstra也就是单源最短路算法,能求出某个点到其他所有点的最短路
首先对于一个空集合,最少要进行$n$次操作,才能把所有点加入集合
然后对于每次加点,就要循环$n$次找出离集合最近的点,然后再次更新,dis数组
复杂度:$O(n^2)$
1 | void Dijkstra(int x){//x是原点 |
堆优化Dijkstra算法
万一$n$很大,上面的算法就会力不从心,我们用到c++的优先队列,priority_queue
假定我们知道优先队列怎么用(cppreference),我们可以$logn$的找出集合外中哪个点的dis[i]最小,那么就把复杂度降低到$nlogn$,一般用上面足够了,下面还包含链式前向星的写法,可以学习一波哦
1 | struct node{ |
Floyd算法
单源最短路我们已经解决,如果问你每个点到每个点的最短路呢?就是说我要问任意一点的最短路,那么我们如果用Dijkstra算法,即使用了堆优化也需要$n^3logn$的时间复杂度,Floyd要好那么一点点,只要$n^3$(真的只是一点点)
Floyd的思想很简单,先枚举两个点 $i$ 、$j$点,我再枚举一个$k$点,那么$i$到$j$的最短路,要么通过$k$要么不通过,那么我们取最小值实现局部最优就能使总体最优,代码很简洁
1 | for(int k=1;k<=n;k++){ |
总结
其实上面的算法都是贪心的思想,这是基于无负权边的前提下的,这点需要注意,这就是贪心思想的局限性,局部最优无法使整体最优。