计算完全最短路径的Floyd算法剖析

转载 2017年01月03日 18:15:16

到两个重要矩阵:

        1.d[numVex][numVex]  (numVex图的顶点数):最开始该矩阵就是图的邻接矩阵,经过Floyd算法处理开后,d[numVex][numVex]中的d[i][j],表示着从顶点i到j的最短路径的权重。

        2.p[numVex][numVex]:p[i][j]表示从i到j的最短路径上 i的后继,例如1到5最短路劲为1-2-4-5  那么p[1][5]==2 ,最开始构建的p矩阵中p[i][j]= j


算法核心思想:  三圈for循环 

[java] view plain copy
  1. for (int k = 0; k < graph.getNumVex(); k++) {  
  2.   
  3.                      for (int v = 0; v < graph.getNumVex(); v++) {  
  4.   
  5.                             for (int w = 0; w < graph.getNumVex(); w++) {  
  6.   
  7.                                    if (d[v][w] > d[v][k] + d[k][w]) {  
  8.   
  9.                                           d[v][w] = d[v][k] + d[k][w];  
  10.   
  11.                                           p[v][w] = p[v][k];// p[v][w]是v--w最短路径上 v的下一顶点  
  12.   
  13.                                    }  
  14.   
  15.                             }  
  16.   
  17.                      }  
  18.   
  19.               }  

第一层 k是作为中间顶点

第二层 v是作为起始顶点

第三层 w是作为终点顶点


内层核心代码

以v为起点,w为终点,再以k作为v和w之间的中间点,去判断d[v][ w]和d[v][k] + d[k][w]的大小关系,如果d[v][w] > d[v][k] + d[k][w],说明找到从v→w的更短路径了,此时更改d[v][w]的值为d[v][k] + d[k][w]。

p[v][w]的值也要相应改成p[v][k]的值,因为 p[v][k]的值是v→k最短路径上v的后继顶点,而v→w这段最短路径是连接在v→k这段路径后面的,所以令所当然p[v][w]也要指向p[v][k]。

注意:最外层的k循环,前面的n次循环的结果跟后面n+1次循环的错做过程是息息相关,

          三次循环完成后,各个顶点之间的最短路径权重会存储在d矩阵中:d[i][j]表示i→j的最短路径权重。

 

p中则存储着路径上的顶点,如果把i→j最短路径上的顶点列出来呢?

[java] view plain copy
  1. //求start→end 最短路径上的顶点  
  2.   
  3. StringBuilder path = new StringBuilder();  
  4.   
  5. int index = start;//起始点  
  6.   
  7. path.append(start + " → ");  
  8.   
  9.               while (index != end) {  
  10.   
  11.               //循环取出路径上的各个顶点  
  12.   
  13.                      index = p[index][end];  
  14.   
  15.                      if(index != end){  
  16.   
  17. path.append(index + " →");  
  18.   
  19. }  

用一个while循环循环 index = p[index][end];直到达到终点

假设该最短路径为 start→A→B→C→end

则执行过程是:

[java] view plain copy
  1. index = p[start][end]; →A  
  2.   
  3. path== start→A →  
  4.   
  5.    
  6.   
  7. index = p[A][end]; →B  
  8.   
  9. path== start→A →B →  
  10.   
  11.   
  12.   
  13. index = p[B][end]; →C  
  14.   
  15. path== start→A →B →C→  
  16.   
  17.   
  18.   
  19. index = p[C][end]; →end  
  20.   
  21. path== start→A →B →C→end  

测试

[java] view plain copy
  1. 请输入定点的数目:5  
  2. 顶点数为:5  
  3. 请输入边数:7  
  4. 边数为:7  
  5. 请输入(Vi,Vj)上下标i 和  j,以及权重,用逗号隔开  
  6. 0,1,5  
  7. 0,4,7  
  8. 1,2,4  
  9. 4,2,8  
  10. 1,3,2  
  11. 2,3,6  
  12. 4,3,1  
  13. 初始的d矩阵  
  14. 5 9999 9999 7  
  15. 0 4 2 9999  
  16. 4 0 6 8  
  17. 2 6 0 1  
  18. 9999 8 1 0  
  19.    
  20. 初始的p矩阵  
  21. 1 2 3 4  
  22. 1 2 3 4  
  23. 1 2 3 4  
  24. 1 2 3 4  
  25. 1 2 3 4  
  26.    
  27. 处理后的d矩阵  
  28. 5 9 7 7  
  29. 0 4 2 3  
  30. 4 0 6 7  
  31. 2 6 0 1  
  32. 3 7 1 0  
  33.    
  34. 处理后的p矩阵  
  35. 1 1 1 4  
  36. 1 2 3 3  
  37. 1 2 3 3  
  38. 1 2 3 4  
  39. 3 3 3 4  
  40.    
  41. 求最短路径  
  42. 请输入起点:  
  43. 请输入终点:  
  44. 02的最短路径为9  
  45. 该路劲为:0 → 1 →2  
  46. 是否继续计算其他最短路径 Y/N?  
  47. y  
  48. 求最短路径  
  49. 请输入起点:  
  50. 请输入终点:  
  51. 03的最短路径为7  
  52. 该路劲为:0 → 1 →3  
  53. 是否继续计算其他最短路径 Y/N?  
  54. y  
  55. 求最短路径  
  56. 请输入起点:  
  57. 请输入终点:  
  58. 41的最短路径为3  
  59. 该路劲为:4 → 3 →1  
  60. 是否继续计算其他最短路径 Y/N?  
  61. y  
  62. 求最短路径  
  63. 请输入起点:  
  64.    
  65. 请输入终点:  
  66. 24的最短路径为7  
  67. 该路劲为:2 → 3 →4  
  68. 是否继续计算其他最短路径 Y/N?  


[java] view plain copy
  1. package DataStructure;  
  2.   
  3. import java.util.Scanner;  
  4.   
  5. public class Floyd {  
  6.     private Graph graph;  
  7.     private int[][] d;// 用来存储顶点到顶点之间最短路径的权重  
  8.     private int[][] p;// p[1][5]表示1到5的最短路径上 1的后继,例如1到5最短路劲为1-2-4-5 那么p[1][5]==2  
  9.   
  10.     public Floyd() {  
  11.         this.graph = new Graph();  
  12.         d = graph.getArc();  
  13.         p = new int[graph.getNumVex()][graph.getNumVex()];  
  14.         initP();// 初始化矩阵p  
  15.         System.out.println("初始的d矩阵\n");  
  16.         for (int i = 0; i < graph.getNumVex(); i++) {  
  17.             for (int j = 0; j < graph.getNumVex(); j++) {  
  18.                 System.out.print(d[i][j] + " ");  
  19.             }  
  20.             System.out.println("\n");  
  21.         }  
  22.         System.out.println("初始的p矩阵\n");  
  23.         for (int i = 0; i < graph.getNumVex(); i++) {  
  24.             for (int j = 0; j < graph.getNumVex(); j++) {  
  25.                 System.out.print(p[i][j] + " ");  
  26.             }  
  27.             System.out.println("\n");  
  28.   
  29.         }  
  30.         work();  
  31.           
  32.         System.out.println("处理后的d矩阵\n");  
  33.         for (int i = 0; i < graph.getNumVex(); i++) {  
  34.             for (int j = 0; j < graph.getNumVex(); j++) {  
  35.                 System.out.print(d[i][j] + " ");  
  36.             }  
  37.             System.out.println("\n");  
  38.         }  
  39.           
  40.         System.out.println("处理后的p矩阵\n");  
  41.         for (int i = 0; i < graph.getNumVex(); i++) {  
  42.             for (int j = 0; j < graph.getNumVex(); j++) {  
  43.                 System.out.print(p[i][j] + " ");  
  44.             }  
  45.             System.out.println("\n");  
  46.         }  
  47.     }  
  48.   
  49.     /** 
  50.      * 初始化p矩阵 
  51.      *  
  52.      */  
  53.     private void initP() {  
  54.         for (int i = 0; i < graph.getNumVex(); i++) {  
  55.             for (int j = 0; j < graph.getNumVex(); j++) {  
  56.                 p[i][j] = j;  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     /** 
  62.      * 对d和p进行变化 
  63.      *  
  64.      */  
  65.     private void work() {  
  66.         for (int k = 0; k < graph.getNumVex(); k++) {  
  67.             for (int v = 0; v < graph.getNumVex(); v++) {  
  68.                 for (int w = 0; w < graph.getNumVex(); w++) {  
  69.                     if (d[v][w] > d[v][k] + d[k][w]) {  
  70.                         d[v][w] = d[v][k] + d[k][w];  
  71.                         p[v][w] = p[v][k];// p[v][w]是v--w最短路径上 v的下一顶点  
  72.                     }  
  73.                 }  
  74.             }  
  75.         }  
  76.     }  
  77.   
  78.     /** 
  79.      * 获取最短路劲 
  80.      *  
  81.      */  
  82.     public void getShortestPath(int start, int end) {  
  83.         StringBuilder path = new StringBuilder();  
  84.         int index = start;// 起始点  
  85.         path.append(start + " → ");  
  86.   
  87.         while (index != end) {  
  88.             // 循环取出路径上的各个顶点  
  89.             index = p[index][end];  
  90.             if (index != end) {  
  91.                 path.append(index + " →");  
  92.             }else {  
  93.                 path.append(index);  
  94.             }  
  95.   
  96.         }  
  97.   
  98.         System.out.println("从" + (start) + "到" + (end) + "的最短路径为"  
  99.                 + d[start][end] + "\n该路劲为:" + path.toString());  
  100.     }  
  101.   
  102.     public static void getShortestPath(Floyd floyd) {  
  103.         Scanner scanner = new Scanner(System.in);  
  104.         System.out.println("求最短路径\n请输入起点:");  
  105.         int start = scanner.nextInt();  
  106.         System.out.println("请输入终点:");  
  107.         int end = scanner.nextInt();  
  108.         floyd.getShortestPath(start, end);  
  109.         System.out.println("是否继续计算其他最短路径 Y/N? ");  
  110.         String tag = scanner.next();  
  111.         if (tag.toLowerCase().equals("y")) {  
  112.             getShortestPath(floyd);  
  113.         }  
  114.   
  115.     }  
  116.   
  117.     /** 
  118.      * 图内部类 
  119.      *  
  120.      * @author ccf 
  121.      *  
  122.      */  
  123.     class Graph {  
  124.         /** 
  125.          * 定点数 
  126.          *  
  127.          */  
  128.         private int numVex = 0;  
  129.         private int arc[][] = null;  
  130.         private int numEdge = 0;  
  131.         private final int INFINITY = 9999;  
  132.   
  133.         public Graph() {  
  134.             System.out.print("请输入定点的数目:");  
  135.             Scanner scanner = new Scanner(System.in);  
  136.             this.numVex = scanner.nextInt();  
  137.             arc = new int[numVex][numVex];  
  138.             for (int i = 0; i < numVex; i++) {  
  139.                 for (int j = 0; j < numVex; j++) {  
  140.                     arc[i][j] = INFINITY;  
  141.                 }  
  142.             }  
  143.             for (int i = 0; i < numVex; i++) {  
  144.                 arc[i][i] = 0;  
  145.   
  146.             }  
  147.             System.out.println("顶点数为:" + this.numVex);  
  148.             System.out.print("请输入边数:");  
  149.             scanner = new Scanner(System.in);  
  150.             this.numEdge = scanner.nextInt();  
  151.             System.out.println("边数为:" + this.numEdge);  
  152.   
  153.             System.out.println("请输入(Vi,Vj)上下标i 和  j,以及权重,用逗号隔开");  
  154.             for (int i = 1; i <= numEdge; i++) {  
  155.                 scanner = new Scanner(System.in);  
  156.                 String a = scanner.nextLine();  
  157.                 String[] b = a.split(",");  
  158.                 // System.out  
  159.                 // .println("输入了:" + Integer.parseInt(b[0]) + " "  
  160.                 // + Integer.parseInt(b[1]) + " "  
  161.                 // + Integer.parseInt(b[2]));  
  162.                 arc[Integer.parseInt(b[0])][Integer.parseInt(b[1])] = Integer  
  163.                         .parseInt(b[2]);  
  164.                 arc[Integer.parseInt(b[1])][Integer.parseInt(b[0])] = Integer  
  165.                         .parseInt(b[2]);  
  166.   
  167.             }  
  168.               
  169.         }  
  170.   
  171.         public int[][] getArc() {  
  172.             return arc;  
  173.         }  
  174.   
  175.         public int getNumVex() {  
  176.             return numVex;  
  177.         }  
  178.   
  179.     }  
  180.   
  181.     public static void main(String[] args) {  
  182.         Floyd floyd = new Floyd();  
  183.         getShortestPath(floyd);  
  184.     }  
  185.   
  186. }  

相关文章推荐

多源最短路径问题-弗洛伊德(Floyd)算法

要获得任意两点之间的最短距离,也可以通过多次调用求解单源最短路径的算法来实现。但Floyd算法来实现会更简单。 算法步骤...

Floyd算法求最短路径

  • 2009年01月03日 11:14
  • 3KB
  • 下载

C例子:最短路径(floyd算法)

  • 2015年10月11日 10:18
  • 2KB
  • 下载

结点对最短路径之Floyd算法原理详解及实现

上两篇博客介绍了计算单源最短路径的Bellman-Ford算法和Dijkstra算法。Bellman-Ford算法适用于任何有向图,即使图中包含负环路,它还能报告此问题。Dijkstra算法运行速度比...

最短路径floyd算法

  • 2010年09月18日 17:25
  • 322KB
  • 下载

#1089 : 最短路径·二:Floyd算法

#1089 : 最短路径·二:Floyd算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的中午,小Hi和小H...

用floyd算法时间最短路径

  • 2008年06月14日 21:16
  • 7KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:计算完全最短路径的Floyd算法剖析
举报原因:
原因补充:

(最多只允许输入30个字)