当前位置:   article > 正文

C语言 最短路径 弗洛伊德(Floyd)算法_floyd-warshall算法

floyd-warshall算法

前言

Floyd-Warshall 算法最初由 Robert W. Floyd 于 1962 年提出,之后由 Stephen Warshall 在 1962 年再次发现。Floyd 的原始论文标题为“算法97:最短路程问题”,而 Warshall 的文献中将其命名为 Floyd-Warshall 算法。

Floyd-Warshall 算法是用于解决所有节点对之间的最短路径问题的算法。该算法采用动态规划的思想,通过中间节点迭代更新每对节点之间的最短路径,其基本思想是将问题分解成许多子问题,并逐步解决这些子问题,最终得到全局最优解。

Floyd-Warshall 算法具有很高的效率和广泛的应用,是解决最短路径问题的重要算法之一,被广泛用于网络路由、城市交通规划、电路布线、物流配送等领域。同时,弗洛伊德算法也是其他算法(如 Dijkstra 算法)的基础,在一定程度上影响了后来的研究和发展。


 下图所示为通过弗洛伊德算法求每对顶点间最短路径步骤:


 视频讲解:

弗洛伊德算法


算法实现

基本流程:

  1. 初始化:创建一个大小为n×n的矩阵distance,表示任意两个节点之间的最短路径长度,并将其初始化为图中边的权值。对于不存在的边,将其权值设为无穷大。
  2. 中间节点迭代:依次考虑图中的每个节点作为中间节点的情况,对于每个节点i和j,若经过中间节点k能够使得i到j的路径更短,则更新distance[i][j]的值为distance[i][k]+distance[k][j]。
  3. 输出结果:矩阵 distance 中的值即为任意两个节点之间的最短路径长度。
  1. //弗洛伊德算法
  2. void Floyd(AMGraph* G) {
  3. int distance[MVNum][MVNum];
  4. int i, j, k;
  5. //初始化距离矩阵
  6. for (i = 0; i < G->vexnum; i++) {
  7. for (j = 0; j < G->vexnum; j++) {
  8. distance[i][j] = G->arcs[i][j];
  9. }
  10. }
  11. //中间节点迭代
  12. for (k = 0; k < G->vexnum; k++) {
  13. for (i = 0; i < G->vexnum; i++) {
  14. for (j = 0; j < G->vexnum; j++) {
  15. if (distance[i][k] + distance[k][j] < distance[i][j]) {
  16. distance[i][j] = distance[i][k] + distance[k][j];
  17. }
  18. }
  19. }
  20. }
  21. //输出
  22. printf("每对顶点间的最短距离:\n");
  23. for (i = 0; i < G->vexnum; i++) {
  24. for (j = 0; j < G->vexnum; j++) {
  25. if (distance[i][j] == MaxInt) {
  26. printf("∞ ");
  27. }
  28. else {
  29. printf("%d ", distance[i][j]);
  30. }
  31. }
  32. printf("\n");
  33. }
  34. }

运行代码构造上图的无向网的邻接矩阵,输出最短距离矩阵: 


源代码:

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <malloc.h>
  5. #define MVNum 100//最大顶点数
  6. #define MaxInt 66666//表示极大值
  7. typedef struct {
  8. char vexs[MVNum];//顶点表(顶点为字符型)
  9. int arcs[MVNum][MVNum];//邻接矩阵(权值为整型)
  10. int vexnum, arcnum;//图的当前点数和边数
  11. }AMGraph;
  12. //定位
  13. int LocateVex(AMGraph* G, char v) {
  14. int i;
  15. for (i = 0; i < G->vexnum; i++) {
  16. if (G->vexs[i] == v) {
  17. return i;
  18. }
  19. }
  20. return -1;
  21. }
  22. //无向网的建立
  23. AMGraph* CreateUDN() {
  24. int i, j, k, w;
  25. char v1, v2;
  26. AMGraph* G = malloc(sizeof(AMGraph));
  27. printf("输入总顶点数,边数\n");
  28. scanf("%d%d", &G->vexnum, &G->arcnum);
  29. getchar();//吸收换行符
  30. printf("依次输入点的信息\n");
  31. for (i = 0; i < G->vexnum; i++) {
  32. scanf("%c", &G->vexs[i]);
  33. }
  34. getchar();//吸收换行符
  35. for (i = 0; i < G->vexnum; i++)
  36. for (j = 0; j < G->vexnum; j++) {
  37. if (i == j) {
  38. G->arcs[i][j] = 0;
  39. }
  40. else {
  41. G->arcs[i][j] = MaxInt;
  42. }
  43. }
  44. for (k = 0; k < G->arcnum; k++) {
  45. printf("输入一条边依附的顶点及权值\n");
  46. scanf("%c%c", &v1, &v2);
  47. scanf("%d", &w);
  48. getchar();//吸收换行符
  49. i = LocateVex(G, v1), j = LocateVex(G, v2);//确定v1、v2在顶点数组的下标
  50. G->arcs[i][j] = w;//<v1,v2>权值置为w
  51. G->arcs[j][i] = w;//无向网对称边<v2,v2>权值也置为w
  52. }
  53. return G;
  54. }
  55. //输出邻接矩阵
  56. void print(AMGraph* G) {
  57. int i, j;
  58. printf(" ");
  59. for (i = 0; i < G->vexnum; i++) {
  60. printf("%c ", G->vexs[i]);
  61. }
  62. printf("\n");
  63. for (i = 0; i < G->vexnum; i++) {
  64. printf("%c ", G->vexs[i]);
  65. for (j = 0; j < G->vexnum; j++) {
  66. if (G->arcs[i][j] == MaxInt)
  67. printf("∞ ");
  68. else
  69. printf("%d ", G->arcs[i][j]);
  70. }
  71. printf("\n");
  72. }
  73. }
  74. //弗洛伊德算法
  75. void Floyd(AMGraph* G) {
  76. int distance[MVNum][MVNum];
  77. int i, j, k;
  78. //初始化距离矩阵
  79. for (i = 0; i < G->vexnum; i++) {
  80. for (j = 0; j < G->vexnum; j++) {
  81. distance[i][j] = G->arcs[i][j];
  82. }
  83. }
  84. //中间节点迭代
  85. for (k = 0; k < G->vexnum; k++) {
  86. for (i = 0; i < G->vexnum; i++) {
  87. for (j = 0; j < G->vexnum; j++) {
  88. if (distance[i][k] + distance[k][j] < distance[i][j]) {
  89. distance[i][j] = distance[i][k] + distance[k][j];
  90. }
  91. }
  92. }
  93. }
  94. //输出
  95. printf("每对顶点间的最短距离:\n");
  96. for (i = 0; i < G->vexnum; i++) {
  97. for (j = 0; j < G->vexnum; j++) {
  98. if (distance[i][j] == MaxInt) {
  99. printf("∞ ");
  100. }
  101. else {
  102. printf("%d ", distance[i][j]);
  103. }
  104. }
  105. printf("\n");
  106. }
  107. }
  108. int main() {
  109. AMGraph* G = CreateUDN();
  110. printf("该无向网邻接矩阵为:\n");
  111. print(G);
  112. Floyd(G);
  113. }

总结

弗洛伊德算法是一种解决图中多源最短路径问题的算法,可以求出图中任意两个节点之间的最短路径长度。该算法的时间复杂度为O\left ( n^{3} \right ),空间复杂度为O\left ( n^{2} \right )。 

需要指出的是,虽然弗洛伊德算法能够解决任意两个节点之间的最短路径问题,但在某些情况下可能不是最优解。因此,在实际使用中,需要根据具体需求选择合适的算法。

总之,弗洛伊德算法作为图论领域中的经典算法,其思想和方法都值得我们深入学习和掌握,以便能够更好地应对实际问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/797428
推荐阅读