弗洛伊德(Floyd)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。

    Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法是一种在具有正或负边缘权重(但没有负环)的加权图中找到最短路径的算法

    算法分析:弗洛伊德(Floyd)算法 - 图1

    弗洛伊德(Floyd)算法和迪杰斯特拉(Dijkstra)算法的区别:
    1、Floyd算法本质是贪心算法;Dijkstra算法本质是动态规划算法。
    2、Floyd算法偏重于多源最短路径的求解,即能够求出任意两个节点的最短路径;Dijkstra肃算法是单源最短路径的求解,能够求一个节点到其余所有节点的最短路径。
    3、Floyd算法支持正权重或负权重;Dijkstra算法只支持正权重。

    1. /**
    2. * 《Floyd算法》
    3. * 弗洛伊德(Floyd)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
    4. * Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法是一种在具有正或负边缘权重(但没有负环)的加权图中找到最短路径的算法
    5. *
    6. * 基本思想
    7. * 通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入一个矩阵S,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。
    8. * 假设图G中顶点个数为N,则需要对矩阵S进行N次更新。初始时,矩阵S中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞。
    9. * 接下来开始,对矩阵S进行N次更新。第1次更新时,如果"a[i][j]的距离" > "a[i][0]+a[0][j]"(a[i][0]+a[0][j]表示"i与j之间经过第1个顶点的距离"),则更新a[i][j]为"a[i][0]+a[0][j]"。
    10. * 同理,第k次更新时,如果"a[i][j]的距离" > "a[i][k]+a[k][j]",则更新a[i][j]为"a[i][k]+a[k][j]"。更新N次之后,操作完成!
    11. *
    12. * 最佳应用
    13. * 胜利乡有7个村庄(A, B, C, D, E, F, G),请问从各个村庄分别到达其他村庄的最短路径
    14. *
    15. * 5
    16. * 【A】--【B】
    17. * 7 / \ / \ 9
    18. * / 2 \ / 3 \
    19. * 【C】 【G】 【D】
    20. * \ 4/ \6 /
    21. * 8 \ / \ / 4
    22. * 【E】--【F】
    23. * 5
    24. */
    25. public class Floyd {
    26. /**
    27. * floyd最短路径
    28. * 即,统计图中各个顶点间的最短路径。
    29. */
    30. public static void minPath(ArrayGraph graph) {
    31. // 路径数组 path[i][j]=k表示,"顶点i"到"顶点j"的最短路径会经过顶点k。
    32. Integer[][] path = new Integer[graph.size()][graph.size()];
    33. // 长度数组 dist[i][j]=sum表示,"顶点i"到"顶点j"的最短路径的长度是sum。
    34. Integer[][] dist = new Integer[graph.size()][graph.size()];
    35. // 初始化
    36. Object[][] array = graph.getEdgeArray();
    37. for (int i = 0; i < array.length; i++) {
    38. for (int j = 0; j < array[i].length; j++) {
    39. // "顶点i"到"顶点j"的路径长度为"i到j的权值"
    40. dist[i][j] = (Integer) array[i][j];
    41. // "顶点i"到"顶点j"的最短路径是经过顶点j。
    42. path[i][j] = j;
    43. }
    44. }
    45. // 计算最短路径
    46. for (int k = 0; k < graph.size(); k++) {
    47. for (int i = 0; i < graph.size(); i++) {
    48. for (int j = 0; j < graph.size(); j++) {
    49. // 如果经过下标为k顶点路径比原两点间路径更短,则更新dist[i][j]和path[i][j]
    50. Integer tmp = (dist[i][k] == null || dist[k][j] == null) ? null : (dist[i][k] + dist[k][j]);
    51. if (tmp != null) {
    52. if (dist[i][j] == null || dist[i][j] > tmp) {
    53. // "i到j最短路径"对应的值设,为更小的一个(即经过k)
    54. dist[i][j] = tmp;
    55. // "i到j最短路径"对应的路径,经过k
    56. path[i][j] = path[i][k];
    57. }
    58. }
    59. }
    60. }
    61. }
    62. // 打印floyd最短路径的结果
    63. System.out.println("Floyd算法求最短路径:");
    64. for (int i = 0; i < dist.length; i++) {
    65. for (int j = 0; j < dist[i].length; j++) {
    66. System.out.printf("%2d ", dist[i][j]);
    67. }
    68. System.out.printf("\n");
    69. }
    70. }
    71. public static void main(String[] args) {
    72. ArrayGraph<String, Integer> graph = new ArrayGraph(7);
    73. // 添加顶点
    74. graph.addVertex("A");
    75. graph.addVertex("B");
    76. graph.addVertex("C");
    77. graph.addVertex("D");
    78. graph.addVertex("E");
    79. graph.addVertex("F");
    80. graph.addVertex("G");
    81. // 添加边
    82. graph.addEdge("A", "B", 5);
    83. graph.addEdge("A", "C", 7);
    84. graph.addEdge("A", "G", 2);
    85. graph.addEdge("B", "G", 3);
    86. graph.addEdge("B", "D", 9);
    87. graph.addEdge("C", "E", 8);
    88. graph.addEdge("E", "F", 5);
    89. graph.addEdge("E", "G", 4);
    90. graph.addEdge("F", "G", 6);
    91. graph.addEdge("D", "F", 4);
    92. System.out.println("打印村庄的图:");
    93. graph.print();
    94. System.out.println();
    95. // floyd最短路径
    96. Floyd.minPath(graph);
    97. }
    98. }