1. 程式人生 > >無向圖的最短路徑求解演算法之——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. public
    class ShortestDistanceOfTwoPoint_V5 {  
  4. publicstaticint dijkstra(int[][] W1, int start, int end) {  
  5. boolean[] isLabel = newboolean[W1[0].length];// 是否標號
  6. int[] indexs = newint[W1[0].length];// 所有標號的點的下標集合,以標號的先後順序進行儲存,實際上是一個以陣列表示的棧
  7. int i_count = -1;//棧的頂點
  8. int[] distance = W1[start].clone();// v0到各點的最短距離的初始值
  9. int index = start;// 從初始點開始
  10. int presentShortest = 0;//當前臨時最短距離
  11.         indexs[++i_count] = index;// 把已經標號的下標存入下標集中
  12.         isLabel[index] = true;  
  13. while (i_count<W1[0].length) {  
  14. // 第一步:標號v0,即w[0][0]找到距離v0最近的點
  15. int min = Integer.MAX_VALUE;  
  16. for (int i = 0; i < distance.length; i++) {  
  17. if (!isLabel[i] && distance[i] != -1 && i != index) {  
  18. // 如果到這個點有邊,並且沒有被標號
  19. if (distance[i] < min) {  
  20.                         min = distance[i];  
  21.                         index = i;// 把下標改為當前下標
  22.                     }  
  23.                 }  
  24.             }  
  25. if (index == end) {//已經找到當前點了,就結束程式
  26. break;  
  27.             }  
  28.             isLabel[index] = true;//對點進行標號
  29.             indexs[++i_count] = index;// 把已經標號的下標存入下標集中
  30. if (W1[indexs[i_count - 1]][index] == -1
  31.                     || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  
  32. // 如果兩個點沒有直接相連,或者兩個點的路徑大於最短路徑
  33.                 presentShortest = distance[index];  
  34.             } else {  
  35.                 presentShortest += W1[indexs[i_count - 1]][index];  
  36.             }  
  37. // 第二步:將distance中的距離加入vi
  38. for (int i = 0; i < distance.length; i++) {  
  39. // 如果vi到那個點有邊,則v0到後面點的距離加
  40. if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可達,則現在可達了
  41.                     distance[i] = presentShortest + W1[index][i];  
  42.                 } elseif (W1[index][i] != -1
  43.                         && presentShortest + W1[index][i] < distance[i]) {  
  44. // 如果以前可達,但現在的路徑比以前更短,則更換成更短的路徑
  45.                     distance[i] = presentShortest + W1[index][i];  
  46.                 }  
  47.             }  
  48.         }  
  49. //如果全部點都遍歷完,則distance中儲存的是開始點到各個點的最短路徑
  50. return distance[end] - distance[start];  
  51.     }  
  52. publicstaticvoid main(String[] args) {  
  53. // 建立一個權值矩陣
  54. int[][] W1 = { //測試資料1
  55.                 { 014, -1, -1, -1 },  
  56.                 { 10275, -1 },  
  57.                 { 420, -11, -1 },   
  58.                 { -17, -1032 },  
  59.                 { -151306 },   
  60.                 { -1, -1, -1260 } };  
  61. int[][] W = { //測試資料2
  62.                 { 0134 },  
  63.                 { 102, -1 },  
  64.                 { 3205 },  
  65.                 { 4, -150 } };  
  66.         System.out.println(dijkstra(W1, 0,4));  
  67.     }  
  68. }  

如果需要求無向圖各個點的最短距離矩陣,則多次運用dijkstra演算法就可以了,程式碼如下:

  1. package com.xh.Dijkstra;  
  2. //這個程式用來求得一個圖的最短路徑矩陣
  3. publicclass ShortestDistance_V4 {  
  4. publicstaticint dijkstra(int[][] W1, int start, int end) {  
  5. boolean[] isLabel = newboolean[W1[0].length];// 是否標號
  6. int min = Integer.MAX_VALUE;  
  7. int[] indexs = newint[W1[0].length];// 所有標號的點的下標集合
  8. int i_count = -1;  
  9. int index = start;// 從初始點開始
  10. int presentShortest = 0;  
  11. int[] distance = W1[start].clone();// v0到各點的最短距離的初始值
  12.         indexs[++i_count] = index;// 把已經標號的下標存入下標集中
  13.         isLabel[index] = true;  
  14. while (true) {  
  15. // 第一步:標號v0,即w[0][0]找到距離v0最近的點
  16.             min = Integer.MAX_VALUE;  
  17. for (int i = 0; i < distance.length; i++) {  
  18. if (!isLabel[i] && distance[i] != -1 && i != index) {  
  19. // 如果到這個點有邊,並且沒有被標號
  20. if (distance[i] < min) {  
  21.                         min = distance[i];  
  22.                         index = i;// 把下標改為當前下標
  23.                     }  
  24.                 }  
  25.             }  
  26. if (index == end) {  
  27. break;  
  28.             }  
  29.             isLabel[index] = true;  
  30.             indexs[++i_count] = index;// 把已經標號的下標存入下標集中
  31. if (W1[indexs[i_count - 1]][index] == -1
  32.                     || presentShortest + W1[indexs[i_count - 1]][index] > distance[index]) {  
  33.                 presentShortest = distance[index];  
  34.             } else {  
  35.                 presentShortest += W1[indexs[i_count - 1]][index];  
  36.             }  
  37. // 第二步:獎distance中的距離加入vi
  38. for (int i = 0; i < distance.length; i++) {  
  39. // 如果vi到那個點有邊,則v0到後面點的距離加
  40. // 程式到這裡是有問題滴! 呵呵
  41. if (distance[i] == -1 && W1[index][i] != -1) {// 如果以前不可達,則現在可達了
  42.                     distance[i] = presentShortest + W1[index][i];  
  43.                 } elseif (W1[index][i] != -1
  44.                         && presentShortest + W1[index][i] < distance[i]) {  
  45. // 如果以前可達,但現在的路徑比以前更短,則更換成更短的路徑
  46.                     distance[i] = presentShortest + W1[index][i];  
  47.                 }  
  48.             }  
  49.         }  
  50. return distance[end] - distance[start];  
  51.     }  
  52. publicstaticint[][] getShortestPathMatrix(int[][] W) {  
  53. int[][] SPM = newint[W.length][W.length];  
  54. //多次利用dijkstra演算法
  55. for (int i = 0; i < W.length; i++) {  
  56. for (int j = i + 1; j < W.length; j++) {  
  57.                 SPM[i][j] =dijkstra(W, i, j);  
  58.                 SPM[j][i] = SPM[i][j];  
  59.             }  
  60.         }  
  61. return SPM;  
  62.     }  
  63. publicstaticvoid main(String[] args) {  
  64. /* 頂點集:V={v1,v2,……,vn} */
  65. int[][] W = { { 0134 }, { 102, -

    相關推薦

    路徑dijkstra演算法

    #include <iostream> using namespace std; const int maxnum = 100; const int maxint = 999999; //Dijkstra(n, 1, dist, prev, c); v

    How Many Maos Does the Guanxi Worth(路徑大值)

    Guanxi" is a very important word in Chinese. It kind of means "relationship" or "contact". Guanxi can be based on friendship, but also can be built on

    六度分離 (路徑問題)

    1967年,美國著名的社會學家斯坦利·米爾格蘭姆提出了一個名為“小世界現象(small world phenomenon)”的著名假說,大意是說,任何2個素不相識的人中間最多隻隔著6個人,即只用6個人就可以將他們聯絡在一起,因此他的理論也被稱為“六度分離”理論(six degrees of sepa

    路徑問題

      給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。 Input 輸入n,m,點的編號是1~n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度為d,花費

    [Vijos 2024]路徑短路)

    https://vijos.org/p/2024 題意: 給你圖中每兩個點的最短路,問你可不可以增加一條邊的權值,使最小值不受影響,讓這個最大值最大。 思路:一個圖已經給定了,怎樣才能增加一個邊的權值使他最小值不受影響呢,應該可以想到就是當一個點可以被鬆弛的時候 我們可以

    2017-10-7 vijos 路徑

    描述 無向圖最短路徑問題,是圖論中最經典也是最基礎的問題之一。本題我們考慮一個有 nn 個結點的無向圖 GG。 GG 是簡單完全圖,也就是說 GG 中沒有自環,也沒有重邊,但任意兩個不同的結點之間都有一條帶權的雙向邊。 每一條邊的邊權是非負實數,但我們並不

    拓撲排序+路徑環加權有路徑演算法

    特點:        1、線性時間內解決單點最短路徑問題        2、能夠處理負權邊問題        3、能夠找出最長路徑 不足:因為是基於拓撲排序的,所以不能解決帶環的問題  import java.util.ArrayList; import java.util

    迪傑斯特拉(Dijkstra演算法--網路路徑

    與有向網路不同的是,無向網路的鄰接矩陣是對稱的,所以在構造鄰接矩陣的時候要注意。Dijkstra演算法的具體內容參照我上次寫的迪傑斯特拉(Dijstra)演算法——有向網路最短路徑 下面直接放程式碼和例項,以便更加理解使用。 #include<stdio.

    Til the Cows Come Home (有路徑問題)

    One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the big cow party to be held at far

    求有路徑條數

    (2)Dijkstra演算法 使用兩次Dij演算法,第一次計算最短路徑,第二次計算路徑條數。 int cost[MAX][MAX],dist[MAX],dist2[MAX],num[MAX][MAX]={{0,0}},ci[MAX]={0}; //dist2[]是在第二次寫dijikstra時,記錄最短路

    論-BFS解無權有路徑距離

    概述 本篇部落格主要內容: 對廣度優先搜尋演算法(Breadth-First-Search)進行介紹; 介紹用鄰接表的儲存結構實現一個圖(附C++實現原始碼); 介紹用BFS演算法求解無權有向圖(附C++實現原始碼)。 廣度優先搜尋演算法(Breadt

    hdu6311(路徑覆蓋->尤拉路徑->fleury 尤拉路徑模板)

    這題主要是個套路。。就是求無向圖最小路徑覆蓋。。 與有向圖的二分圖做法不同,這個是轉化為求最少的尤拉路徑。。 尤拉圖有個結論是尤拉路徑的個數為度為奇數的點的個數/2(可以類比歐拉回路的結論) 然後求尤拉路徑的方法是fleury演算法。。其思想就是暴力dfs,然後巧妙的地

    路徑(二)—Dijkstra演算法(通過邊實現鬆弛:鄰接矩陣)

    上一節通過Floyd-Warshall演算法寫了多源節點最短路徑問題: 這一節來學習指定一個點(源點)到其餘各個頂點的最短路徑。也叫做“單源最短路徑”Dijkstra。 例如求下圖中1號頂點到2、3、4、5、6號頂點的最短路徑。 用二維陣列e儲存頂點之間邊的關係,初

    路徑算法Dijkstra算法

    最終 ID max htable tab 過程 ini a算法 主循環 參考:《大話數據結構》 這是一個按照路徑長度遞增的次序產生最短路徑的算法。它並不是一次求出源點到目標點的最短路徑,而是一步步求出它們之間頂點的最短路徑,過程中都是基於已經求出的最短路徑的基礎上,求得

    路徑求解演算法——Dijkstra演算法

    在準備ACM比賽的過程中,研究了圖論中一些演算法。首先研究的便是最短路的問題。《離散數學》第四版(清華大學出版社)一書中講解的Dijkstra演算法是我首先研究的源材料。       如何求圖中V0到V5的最短路徑呢?         java實現的方式如下:   

    的無權路徑演算法與帶權Dijkstra演算法

      最短路徑演算法是圖論中的常見問題,在實際中有著較為廣泛的應用,比如查詢從一個地方到另一個地方的最快方式。問題可以概括為,對於某個輸入頂點s,給出s到所有其它頂點的最短路徑。水平有限,暫時先對這個問題的求解做簡單記錄。   無權圖是有權最短路徑的特例,即邊的權重均是1。演

    無權路徑問題——BFS求解

    解釋 圖1 如圖1所示,這是一個有向無權圖,如果選中某個定點作為起始頂點s,我們要找出s到其他所有頂點的最短路徑問題。由於是無權的,所以我們只關心最短路徑所包含的邊數。這就是

    路徑——迪傑斯坷垃演算法(有、單源路徑

    最短路徑的演算法有兩種:迪傑斯坷垃演算法和弗洛伊德演算法。 但是兩種演算法各有優劣: 迪傑斯坷垃演算法適合單源點最短路徑的獲取, 弗洛伊德演算法適合各點間最短路徑的獲取,即多源點最短路徑的獲取; 今天主要講解迪傑斯坷垃演算法。 一、演算法步驟: 1、獲取鄰接矩陣,確定起始點

    51 nod 1212 小生成樹(Kruckal演算法/Prime演算法圖解)

    1212 無向圖最小生成樹 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。  收起 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 -

    藍書(演算法競賽進階指南)刷題記錄——POJ1734 Sightseeing trip(小環)

    題目:poj1734. 題目大意:給定一張無向圖,求這張無向圖邊權和最小的節點大於3個的環,若有解輸出任意一個方案,否則輸出“No solution.”. 這就是一個較為簡單的floyd應用. 我們可以先把floyd模板寫下來看看floyd有什麼特殊的性質: void floyd