最短路问题的各种算法总结
一、
Floyd算法:
适用范围:任意两点间的最短路
时间复杂度:
特点:允许负权,不允许负权回路(此时显然没有最小回路,越跑越小)
变形及应用:传递闭包+最短路径条数+最小环+最大边最小+最小边最大
核心:三角松弛技术(若有更优的则更新)
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
初始化:
memset(d,0x3f,sizeof(d));
d[i][i]=0
d[i][j]=a[i][j]
重点:K层必须放在外部,k一定是由k-1更新而来。k是决定i到j的最短路径由k更新,故对于每一个k都必须从新跑所有的i和j
实际上原本公式是三维的,常见的是优化后的
原本的转移方程:
应用:
①最大边最小+最小边最大
d[i][j]=min(d[i][j],max(d[i][k],d[k][j])) //最大边最小
d[i][j]=max(d[i][j],min(d[i][k],d[k][j])) //最小边最大
②传递闭包问题:
定义:若干个元素以及二元关系,并且关系具有传递性。通过传递性能推导出尽量多的元素直接的关系,这类问题称为传递闭包。
初始状态:
1<=i<j<k
特别注意:
①注意循环的边界 执行第k层时实际存下的是k-1层的东西 故第一个
②
③注意顺序,一定是先更新最小环再更新最短路(因为更新最短路更新的是第k层,而更新最小环用到的是k-1层,不超过k-1层的最短路是已经求好了的,可以直接用)
④因为权值和有可能比较大,会爆int,所以需要用long long。 但要注意不可以直接开long long类型,否则一开始赋初始值不好操作,三个long long 加起来可能爆 。不如直接加一步强制转换,把一个int变成long long,后面就不可能爆了。
二、
Dijkstra算法
时间复杂度:
特点:单源最短路径问题--->给定起点 n<=3000
特点:不允许存在负权
核心原理:贪心
每次找到相连的边权最小的点,加入队列,等待用这个点去松弛别的点(前提没有负边)
优先队列优化:
三、Bellman-Ford算法
时间复杂度:
没什么优秀的特质,不如SPFA
四、SPFA算法
特点:单源最短路+可以判负环+复杂度一般情况下不错
期望的时间复杂度:
实际情况下有时会被卡成
本质:Bellman_ford的优化
思想:只有被松弛过的点才有可能松弛其他点(否则既然当前都不是最优那用这个点去松弛别人就没意义了)
判负环:如果入队次数>n 注意不是松弛次数 一个点多次被松弛不一定就有负环 可能是重边
双端队列优化:SLF