Floyd算法,也称为Floyd-Warshall算法,是一种用于解决多源最短路径问题的算法。它可以用于计算任意两点之间的最短路径,并可以用于解决其他相关问题,例如最短路径树和最长路径。
Floyd算法的工作原理是通过动态规划来计算所有点对之间的最短路径。它首先初始化一个距离矩阵,其中每个元素表示两个点之间的初始距离。然后,算法迭代地更新距离矩阵,每次更新都会考虑通过中间节点的路径。
Floyd算法的具体步骤如下:
状态转移方程为:
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
其中dp[a][b]
的意思可以理解为点a到点b的最短路径,所以dp[i][k]
的意思可以理解为i到k的最短路径dp[k][j]
的意思为k到j的最短路径.
咱们图解一个案例,初始情况每个点只知道和自己直接相连的点的距离,而其他间接相连的点还不知道距离,比如A-B=2,A-C=3但是B-C在不经过计算的情况是不知道长度的。
加入第一个节点A
进行更新计算,大家可以发现,由于A的加入,使得本来不连通的B,C
点对和B,D
点对变得联通,并且加入A后距离为当前最小,同时你可以发现加入A
其中也使得C-D
多一条联通路径(6+3),但是C-D
联通的话距离为9远远大于本来的(C,D)
联通路径2,所以这条不进行更新。
咱们继续加入第二个节点B
,这个点执行和前面A
相同操作进行。对一些点进行更新。因为和B相连的点比较多,可以产生很多新的路径,这里给大家列举一下并做一个说明,这里新路径我统一用1表示,原来长度用0表示。
AF1=AB+BF=6+2=8 < AF0(∞) 进行更新
AE1=AB+BE=2+4=6 < AE0(∞) 进行更新
CE1=CB+BE=5+5=9 < CE0(∞) 进行更新
CF1=CB+BF=5+6=11<CF0(∞) 进行更新
EF1=EB+BF=4+6=10<EF0(∞) 进行更新
当然,也有一些新的路径大于已有路径不进行更新,例如:
AC1=AB+BC=2+5=7>AC0(3) 不更新
AD1=AB+BD=2+8=10>AD0(6) 不更新……
更多路径这里就不一一列举了。
后序加入C、D、E、F都是进行相同的操作,最终全部加完没有路径可以更新就结束停止。实际上这个时候图中的连线就比较多了。这些连线都是代表当前的最短路径。 这也和我们的需求贴合,我们最终要的是所有节点的最短路径。每个节点最终都应该有5条指向不同节点的边! 矩阵对应边值就是点点之间最短路径。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /**************************************************************** * Description: 给定图G,求任意两点的最短路径,Floyd_warshall算法 * Author: Alex Li * Date: 2024-02-23 12:27:10 * LastEditTime: 2024-08-12 21:26:55 ****************************************************************/ #include <iostream> #include <vector> using namespace std; int main() { // 输入图的节点数 int n; cin >> n; // 初始化距离矩阵 dp,大小为 n x n,存储两点之间的最短路径 vector<vector<int> > dp(n, vector<int>(n)); // 初始化距离矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { dp[i][j] = 0; // 节点到自身的距离为 0 } else { dp[i][j] = INT_MAX; // 初始化为无穷大(表示两点之间没有路径) } } } // 输入图的边 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int u, v, w; cin >> u >> v >> w; // 输入起点 u,终点 v 和权重 w dp[u][v] = w; // 更新距离矩阵中的对应值 } } // Floyd-Warshall 算法的核心部分 // 三重循环更新距离矩阵,考虑经过节点 k 的所有可能路径 for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { // 选择直接路径和经过 k 节点的路径中的较小者 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]); } } } // 输出最终的最短路径距离矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cout << dp[i][j] << " "; // 输出从节点 i 到节点 j 的最短路径距离 } cout << endl; // 输出完一行后换行 } return 0; // 返回 0 表示程序执行成功 } |