当前位置:   article > 正文

无向图的最短路径求解算法之——Dijkstra算法

dijkstra算法怎么计算无向图最小路径

    在准备ACM比赛的过程中,研究了图论中一些算法。首先研究的便是最短路的问题。《离散数学》第四版(清华大学出版社)一书中讲解的Dijkstra算法是我首先研究的源材料。

      如何求图中V0到V5的最短路径呢?

        java实现的方式如下: 

       第一步,根据图来建立权值矩阵:

       int[][] W = { 
    {  0,   1,   4,  -1,  -1,  -1 },
    {  1,   0,   2,   7,    5,  -1 },
    {  4,   2,   0,  -1,    1,  -1 },
    { -1,  7,  -1,   0,    3,    2 },
    { -1,  5,    1,   3,   0,    6 },
    { -1, -1,  -1,   2,   6,    0 } };(-1表示两边不相邻,权值无限大)

例如:W[0][2]=4 表示点V0到点V2的权值为4

W[0][3]=-1表示点V0与V3不相邻,所以权值无限大。

第二步:对V0标号;V0到其它点的路径得到 distance: {0,1,4,-1,-1,-1}; 找到V0到各点中权值最小的那个点(标号的点除外,-1代表无限大),故得到1即对应的下标1,得到V1;对V1标号,然后更改V0通过V1到其它点的路径得到 distance: { 0, 1, 3, 8, 6, -1}; 

第三步:找到distance中权值最小的那个点,(标号的点除外)得到V2,对V2标号,然后更改V0通过V1->V2到其它点的路径得到 distance: { 0, 1, 3, 8, 4, -1}; 

第四步:找到distance中权值最小的那个点,(标号的点除外)得到V4,对V4标号,然后更改V0通过V1->V2到其它点的路径得到 distance: { 0, 1, 3, 7, 4, 10}; 

第四步:找到distance中权值最小的那个点,(标号的点除外)得到V3,对V3标号,然后更改V0通过V1->V2到其它点的路径得到 distance: { 0, 1, 3, 7, 4, 9}; 

最后只剩下V5没有被标号,就找到V5了。结束!

源代码如下:

 
 
  1. package com.xh.Dijkstra;  
  2.  
  3. //这个算法用来解决无向图中任意两点的最短路径  
  4. public class ShortestDistanceOfTwoPoint_V5 {  
  5.     public static int dijkstra(int[][] W1, int start, int end) {  
  6.         boolean[] isLabel = new boolean[W1[0].length];// 是否标号  
  7.         int[] indexs = new int[W1[0].length];// 所有标号的点的下标集合,以标号的先后顺序进行存储,实际上是一个以数组表示的栈  
  8.         int i_count = -1;//栈的顶点  
  9.         int[] distance = W1[start].clone();// v0到各点的最短距离的初始值  
  10.         int index = start;// 从初始点开始  
  11.         int presentShortest = 0;//当前临时最短距离  
  12.  
  13.         indexs[++i_count] = index;// 把已经标号的下标存入下标集中  
  14.         isLabel[index] = true;  
  15.           
  16.         while (i_count<W1[0].length) {  
  17.             // 第一步:标号v0,即w[0][0]找到距离v0最近的点  
  18.  
  19.             int min = Integer.MAX_VALUE;  
  20.             for (int i = 0; i < distance.length; i++) {  
  21.                 if (!isLabel[i] && distance[i] != -1 && i != index) {  
  22.                     // 如果到这个点有边,并且没有被标号  
  23.                     if (distance[i] < min) {  
  24.                         min = distance[i];  
  25.                         index = i;// 把下标改为当前下标  
  26.                     }  
  27.                 }  
  28.             }  
  29.             if (index == end) {//已经找到当前点了,就结束程序  
  30.                 break;  
  31.             }  
  32.             isLabel[index] = true;//对点进行标号  
  33.             indexs[++i_count] = index;// 把已经标号的下标存入下标集中  
  34.             if (W1[indexs[i_count - 1]][index] == -1 
  35.                     || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  
  36.                 // 如果两个点没有直接相连,或者两个点的路径大于最短路径  
  37.                 presentShortest = distance[index];  
  38.             } else {  
  39.                 presentShortest += W1[indexs[i_count - 1]][index];  
  40.             }  
  41.  
  42.             // 第二步:将distance中的距离加入vi  
  43.             for (int i = 0; i < distance.length; i++) {  
  44.                 // 如果vi到那个点有边,则v0到后面点的距离加  
  45.                 if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可达,则现在可达了  
  46.                     distance[i] = presentShortest + W1[index][i];  
  47.                 } else if (W1[index][i] != -1 
  48.                         && presentShortest + W1[index][i] < distance[i]) {  
  49.                     // 如果以前可达,但现在的路径比以前更短,则更换成更短的路径  
  50.                     distance[i] = presentShortest + W1[index][i];  
  51.                 }  
  52.  
  53.             }  
  54.         }  
  55.         //如果全部点都遍历完,则distance中存储的是开始点到各个点的最短路径  
  56.         return distance[end] - distance[start];  
  57.     }  
  58.     public static void main(String[] args) {  
  59.         // 建立一个权值矩阵  
  60.         int[][] W1 = { //测试数据1  
  61.                 { 014, -1, -1, -1 },  
  62.                 { 10275, -1 },  
  63.                 { 420, -11, -1 },   
  64.                 { -17, -1032 },  
  65.                 { -151306 },   
  66.                 { -1, -1, -1260 } };  
  67.         int[][] W = { //测试数据2  
  68.                 { 0134 },  
  69.                 { 102, -1 },  
  70.                 { 3205 },  
  71.                 { 4, -150 } };  
  72.  
  73.         System.out.println(dijkstra(W1, 0,4));  
  74.  
  75.     }  
  76. }  

如果需要求无向图各个点的最短距离矩阵,则多次运用dijkstra算法就可以了,代码如下:

 
 
  1. package com.xh.Dijkstra;  
  2.  
  3. //这个程序用来求得一个图的最短路径矩阵  
  4. public class ShortestDistance_V4 {  
  5.     public static int dijkstra(int[][] W1, int start, int end) {  
  6.         boolean[] isLabel = new boolean[W1[0].length];// 是否标号  
  7.         int min = Integer.MAX_VALUE;  
  8.         int[] indexs = new int[W1[0].length];// 所有标号的点的下标集合  
  9.         int i_count = -1;  
  10.         int index = start;// 从初始点开始  
  11.         int presentShortest = 0;  
  12.         int[] distance = W1[start].clone();// v0到各点的最短距离的初始值  
  13.         indexs[++i_count] = index;// 把已经标号的下标存入下标集中  
  14.         isLabel[index] = true;  
  15.         while (true) {  
  16.             // 第一步:标号v0,即w[0][0]找到距离v0最近的点  
  17.  
  18.             min = Integer.MAX_VALUE;  
  19.             for (int i = 0; i < distance.length; i++) {  
  20.                 if (!isLabel[i] && distance[i] != -1 && i != index) {  
  21.                     // 如果到这个点有边,并且没有被标号  
  22.                     if (distance[i] < min) {  
  23.                         min = distance[i];  
  24.                         index = i;// 把下标改为当前下标  
  25.                     }  
  26.                 }  
  27.             }  
  28.             if (index == end) {  
  29.                 break;  
  30.             }  
  31.             isLabel[index] = true;  
  32.             indexs[++i_count] = index;// 把已经标号的下标存入下标集中  
  33.             if (W1[indexs[i_count - 1]][index] == -1 
  34.                     || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  
  35.                 presentShortest = distance[index];  
  36.             } else {  
  37.                 presentShortest += W1[indexs[i_count - 1]][index];  
  38.             }  
  39.  
  40.             // 第二步:奖distance中的距离加入vi  
  41.             for (int i = 0; i < distance.length; i++) {  
  42.                 // 如果vi到那个点有边,则v0到后面点的距离加  
  43.                 // 程序到这里是有问题滴! 呵呵  
  44.                 if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可达,则现在可达了  
  45.                     distance[i] = presentShortest + W1[index][i];  
  46.                 } else if (W1[index][i] != -1 
  47.                         && presentShortest + W1[index][i] < distance[i]) {  
  48.                     // 如果以前可达,但现在的路径比以前更短,则更换成更短的路径  
  49.                     distance[i] = presentShortest + W1[index][i];  
  50.                 }  
  51.  
  52.             }  
  53.         }  
  54.         return distance[end] - distance[start];  
  55.     }  
  56.    
  57.     public static int[][] getShortestPathMatrix(int[][] W) {  
  58.         int[][] SPM = new int[W.length][W.length];  
  59.         //多次利用dijkstra算法  
  60.         for (int i = 0; i < W.length; i++) {  
  61.             for (int j = i + 1; j < W.length; j++) {  
  62.                 SPM[i][j] =dijkstra(W, i, j);  
  63.                 SPM[j][i] = SPM[i][j];  
  64.             }  
  65.         }  
  66.         return SPM;  
  67.     }  
  68.  
  69.     public static void main(String[] args) {  
  70.         /* 顶点集:V={v1,v2,……,vn} */ 
  71.         int[][] W = { { 0134 }, { 102, -1 }, { 3205 },  
  72.                 { 4, -150 } };  
  73.         int[][] W1 = { { 014, -1, -1, -1 }, { 10275, -1 },  
  74.                 { 420, -11, -1 }, { -17, -1032 },  
  75.                 { -151306 }, { -1, -1, -1260 } };// 建立一个权值矩阵  
  76.         ;// 建立一个权值矩阵  
  77.         int[][] D = getShortestPathMatrix(W1);  
  78.         //输出最后的结果  
  79.         for (int i = 0; i < D.length; i++) {  
  80.             for (int j = 0; j < D[i].length; j++) {  
  81.                 System.out.print(D[i][j] + " ");  
  82.             }  
  83.             System.out.println();  
  84.         }  
  85.     }  
  86. }  

如果需要我的学习资料,我非常乐意分享;如果读者能够有所赐教,我甚感荣幸。QQ:810050504(小帅),邮箱是QQ邮箱

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

闽ICP备14008679号