-
多源最短路算法(Floyd)
说到最短路,就不得不提到松弛。
所谓松弛,就是当存在时,令
一般来说,松弛操作后,我们会用松弛后的边不断松弛其他边,而这,就是大部分最短路算法的思路。
思考一下,若用DP的思想考虑,那么我们易设出状态表示从到的最短路,但是这个状态显然具有后效性,因为我们显然无法一遍就能转移出的正确结果,需要不断对其他边进行松弛操作才能得出最后答案,所以同为的值在不同阶段会有不同的值。
那么考虑加一维表示松弛阶段,则最显然表示松弛阶段的方式是边,然而边太多且一个边能松弛其他边的数量及其有限,故考虑点。
则设为只考虑前个点时,从到的最短路。
那么可以推出转移式
不断枚举,然后枚举所有,用这个端点去更新它们。
观察到的值只与有关,故可以用滚动数组压成二维。
代码如下:
for (int k = 1; k <= n; ++k)
for (int u = 1; u <= n; ++u)
for (int v = 1; v <= n; ++v) f[u][v] = min(f[u][v], f[u][k] + f[k][v]); `
-
单源最短路算法(SPFA)
单源最短路只求从一个点出发到达其他点的最短路,故我们不需要把每条边都松弛一遍。
所以很自然地,我们可以想到从与出发点相连的边开始,不断用已经知道的点来松弛其他边,直到再也无法松弛为止,这就是Bellman-Ford单源最短路算法的思路,但这显然很暴力,所以我们需要优化。
不难发现,我们似乎不需要那么多次松弛,我们只需要让每条被松弛的两点间路径再去松弛经过此两点间路径的路径就可以得出每条最短路。
所以考虑代码实现,设表示从起点到的最短路,我们只需要将起点压入队列,对于队列中每个点和其到达的下一个点来说,如果出现了的情况,那么就表示可以被松弛,并且与有关的路径可能有路径的参与会更短,那么对进行松弛操作并把压入队列进行处理,如果队列中没有点了,就说明最短路的搜索已经完成了。
值得注意的是,显然一个点大概率会被入队多次,所以为了尽可能地降低时间复杂度,我们可以用一个数组来表示点是否在队列内,若是在的话就不用再次入队了。显然,当我们处理完一个点时,需要使
这个算法被称作队列优化的Bellman-Ford算法,也被称作SPFA(Shortest Path Faster Algorithm)
代码如下:
void spfa(int st) {
q[++tl] = st, dis[st] = 0, vis[st] = 1;
while (hd <= tl) {
int u = q[hd++];
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (dis[v] > dis[u] + w[i]) {
dis[v] = dis[u] + w[i];
if (!vis[v]) q[++tl] = v, vis[v] = 1;
}
}
vis[u] = 0;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】