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

https://blog.csdn.net/dodott/article/details/52185222

在准备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了。结束!

源代码如下:

package com.xh.Dijkstra;  


//这个算法用来解决无向图中任意两点的最短路径  

public class ShortestDistanceOfTwoPoint_V5 {  

    public static int dijkstra(int[][] W1, int start, int end) {  

        boolean[] isLabel = new boolean[W1[0].length];// 是否标号  

        int[] indexs = new int[W1[0].length];// 所有标号的点的下标集合,以标号的先后顺序进行存储,实际上是一个以数组表示的栈  

        int i_count = -1;//栈的顶点  

        int[] distance = W1[start].clone();// v0到各点的最短距离的初始值  

        int index = start;// 从初始点开始  

        int presentShortest = 0;//当前临时最短距离  


        indexs[++i_count] = index;// 把已经标号的下标存入下标集中  

        isLabel[index] = true;  


        while (i_count

            // 第一步:标号v0,即w[0][0]找到距离v0最近的点  


            int min = Integer.MAX_VALUE;  

            for (int i = 0; i < distance.length; i++) {  

                if (!isLabel[i] && distance[i] != -1 && i != index) {  

                    // 如果到这个点有边,并且没有被标号  

                    if (distance[i] < min) {  

                        min = distance[i];  

                        index = i;// 把下标改为当前下标  

                    }  

                }  

            }  

            if (index == end) {//已经找到当前点了,就结束程序  

                break;  

            }  

            isLabel[index] = true;//对点进行标号  

            indexs[++i_count] = index;// 把已经标号的下标存入下标集中  

            if (W1[indexs[i_count - 1]][index] == -1 

                    || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  

                // 如果两个点没有直接相连,或者两个点的路径大于最短路径  

                presentShortest = distance[index];  

            } else {  

                presentShortest += W1[indexs[i_count - 1]][index];  

            }  


            // 第二步:将distance中的距离加入vi  

            for (int i = 0; i < distance.length; i++) {  

                // 如果vi到那个点有边,则v0到后面点的距离加  

                if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可达,则现在可达了  

                    distance[i] = presentShortest + W1[index][i];  

                } else if (W1[index][i] != -1 

                        && presentShortest + W1[index][i] < distance[i]) {  

                    // 如果以前可达,但现在的路径比以前更短,则更换成更短的路径  

                    distance[i] = presentShortest + W1[index][i];  

                }  


            }  

        }  

        //如果全部点都遍历完,则distance中存储的是开始点到各个点的最短路径  

        return distance[end] - distance[start];  

    }  

    public static void main(String[] args) {  

        // 建立一个权值矩阵  

        int[][] W1 = { //测试数据1  

                { 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 } };  

        int[][] W = { //测试数据2  

                { 0, 1, 3, 4 },  

                { 1, 0, 2, -1 },  

                { 3, 2, 0, 5 },  

                { 4, -1, 5, 0 } };  


        System.out.println(dijkstra(W1, 0,4));  


    }  

}  

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

package com.xh.Dijkstra;  


//这个程序用来求得一个图的最短路径矩阵  

public class ShortestDistance_V4 {  

    public static int dijkstra(int[][] W1, int start, int end) {  

        boolean[] isLabel = new boolean[W1[0].length];// 是否标号  

        int min = Integer.MAX_VALUE;  

        int[] indexs = new int[W1[0].length];// 所有标号的点的下标集合  

        int i_count = -1;  

        int index = start;// 从初始点开始  

        int presentShortest = 0;  

        int[] distance = W1[start].clone();// v0到各点的最短距离的初始值  

        indexs[++i_count] = index;// 把已经标号的下标存入下标集中  

        isLabel[index] = true;  

        while (true) {  

            // 第一步:标号v0,即w[0][0]找到距离v0最近的点  


            min = Integer.MAX_VALUE;  

            for (int i = 0; i < distance.length; i++) {  

                if (!isLabel[i] && distance[i] != -1 && i != index) {  

                    // 如果到这个点有边,并且没有被标号  

                    if (distance[i] < min) {  

                        min = distance[i];  

                        index = i;// 把下标改为当前下标  

                    }  

                }  

            }  

            if (index == end) {  

                break;  

            }  

            isLabel[index] = true;  

            indexs[++i_count] = index;// 把已经标号的下标存入下标集中  

            if (W1[indexs[i_count - 1]][index] == -1 

                    || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  

                presentShortest = distance[index];  

            } else {  

                presentShortest += W1[indexs[i_count - 1]][index];  

            }  


            // 第二步:奖distance中的距离加入vi  

            for (int i = 0; i < distance.length; i++) {  

                // 如果vi到那个点有边,则v0到后面点的距离加  

                // 程序到这里是有问题滴! 呵呵  

                if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可达,则现在可达了  

                    distance[i] = presentShortest + W1[index][i];  

                } else if (W1[index][i] != -1 

                        && presentShortest + W1[index][i] < distance[i]) {  

                    // 如果以前可达,但现在的路径比以前更短,则更换成更短的路径  

                    distance[i] = presentShortest + W1[index][i];  

                }  


            }  

        }  

        return distance[end] - distance[start];  

    }  


    public static int[][] getShortestPathMatrix(int[][] W) {  

        int[][] SPM = new int[W.length][W.length];  

        //多次利用dijkstra算法  

        for (int i = 0; i < W.length; i++) {  

            for (int j = i + 1; j < W.length; j++) {  

                SPM[i][j] =dijkstra(W, i, j);  

                SPM[j][i] = SPM[i][j];  

            }  

        }  

        return SPM;  

    }  


    public static void main(String[] args) {  

        /* 顶点集:V={v1,v2,……,vn} */ 

        int[][] W = { { 0, 1, 3, 4 }, { 1, 0, 2, -1 }, { 3, 2, 0, 5 },  

                { 4, -1, 5, 0 } };  

        int[][] W1 = { { 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 } };// 建立一个权值矩阵  

        ;// 建立一个权值矩阵  

        int[][] D = getShortestPathMatrix(W1);  

        //输出最后的结果  

        for (int i = 0; i < D.length; i++) {  

            for (int j = 0; j < D[i].length; j++) {  

                System.out.print(D[i][j] + " ");  

            }  

            System.out.println();  

        }  

    }  

}  

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • 弗洛伊德算法适用于为图中每一个顶点求最短路径,思路如下 检查图中任何一个 到 任何另一个点能否通过第一个点降低最短...
    RichardW阅读 924评论 0 1
  • 贪心算法 贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上...
    fredal阅读 9,076评论 3 52
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,013评论 0 2
  • 数据结构算法大全(用 PASCAL 描述) 1.数论算法 求两数的最大公约数 function gcd(a,b:i...
    心想事成_ae7e阅读 484评论 0 0
  • 图的定义与术语 1、图按照有无方向分为无向图和有向图。无向图由顶点和边构成,有向图由顶点和弧构成。弧有弧尾和弧头之...
    unravelW阅读 385评论 0 0