最短路徑算法

 在準備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. }  




最短路徑問題—Bellman-Ford算法

一、算法思想

1Dijkstra算法的侷限性

上節介紹了Dijkstra算法,該算法要求網絡中各邊上得權值大於或等於0.如果有向圖中存在帶負權值的邊,則採用Dijkstra算法求解最短路徑得到的結果有可能是錯誤的。

例如,對下圖所示的有向圖,採用Dijkstra算法求得頂點v0到頂點v2的最短距離是dist[2],即v0到v2的直接路徑,長度爲5.但從v0到v2的最短路徑應該是(v0,v1,v2),其長度爲2。

 

 


如果把圖1(a)中的邊<1,2>的權值由-5改成5,則採用Dijkstra算法求解最短路徑,得到的結果是正確的(這裏不再求解)。

爲什麼當有向圖中存在帶負權值的邊時,採用Dijkstra算法求解得到的最短路徑有時是錯誤的?答案是:Dijkstra算法在利用頂點u的dist[]去遞推T集合各頂點的dist[k]值時,前提是頂點u的dist[]值時當前T集合中最短路徑長度最小的。如果圖中所有邊的權值都是正的,這樣推導是沒有問題的。但是如果有負權值的邊,這樣推導是不正確的。例如,在圖1(d)中,第1次在T集合中找到dist[]最小的是頂點2,dist[2]等於5;但是頂點0距離頂點2的最短路徑是(v0,v1,v2),長度爲2,而不是5,其中邊<1,2>是一條負權值邊。

 

2Bellman-Ford算法思想

爲了能夠求解邊上帶有負權值的單源最短路徑問題,Bellman(貝爾曼)和Ford(福特)提出了從源點逐次途經其他頂點,以縮短到達終點的最短路徑長度的方法。該方法也有一個限制條件:要求圖中不能包含權值總和爲負值的迴路。

例如圖2(a)所示的有向圖中,迴路(v0,v1,v0)包括了一條具有負權值的邊,且其路徑長度爲-1。當選擇的路徑爲(v0,v1,v0,v1,v0,v1,v0,v1,…)時,路徑的長度會越來越小,這樣頂點0到頂點2的路徑長度最短可達-∞。如果存在這樣的迴路,則不能採用Bellman-Ford算法求解最短路徑。

如果有向圖中存在由帶負權值的邊組成的迴路,但迴路權值總和非負,則不影響Bellman-Ford算法的求解,如圖2(b)所示。

 

 

 

權值總和爲負值的迴路我們稱爲負權值迴路,在Bellman-Ford算法中判斷有向圖中是否存在負權值迴路的方法,見後面。

假設有向圖中有n個不存在負權值迴路,從頂點v1和到頂點v25如果存在最短路徑,則此路徑最多有n-1條邊。這是因爲如果路徑上得邊數超過了n-1條時,必然會重複經過一個頂點,形成迴路;而如果這個迴路的權值總和爲非負時,完全可以去掉這個迴路,使得v1到v2的最短路徑長度縮短。下面將以此爲依據,計算從源點v0到其他每個頂點u的最短路徑長度dist[u]。

Bellman-Ford算法構造一個最短路徑長度數組序列:dist1[u],dist2[u],dist3[u],…,distn-1[u]。其中:

dist1[u]爲從源點v0到終點u的只經過一條邊的最短路徑的長度,並有dist1[u]=edge[v0,u]。

dist2[u]爲從源點v0出發最多經過不構成負權值迴路的兩條邊到達終點u的最短路徑長度。

dist3[u]爲從源點v0出發最多經過不構成負權值迴路的3條邊到達終點u的最短路徑長度。

……

distn-1[u]爲從源點v0出發最多經過不構成負權值迴路的n-1條邊到達終點u的最短路徑長度。

算法的最終目的是計算出distn-1[u],爲源點v0到頂點u的最短路徑長度。

採用遞推方式計算distk[u]。

設已經求出distk-1[u],u=0,1,…,n-1,此即從源點v0最多經過不構成負權值迴路的k-1條邊到達終點u的最短路徑的長度。

從圖的鄰接矩陣可以找出各個頂點j到達頂點u的(直接邊)距離edge[j,u],計算min{distk-1[j]+edge[j,u]},可得從源點v0途經各個頂點,最多經過不構成迴路的k條邊到達終點u的最短路徑的長度。

比較distk-1[u]和min{distk-1[j]+edge[j,u]},取較小者作爲distk[u]的值。

因此Bellman-Ford算法的遞推公式(求源點v0到各頂點u的最短路徑)爲:

初始:dist1[u]=edge[v0,u],v0是源點

遞推:distk[u]=min{distk-1[u],min{distk-1[j]+edge[j,u]}}

     j=0,1,...,n-1,j<>u; k=2,3,4,...,n-1

 

二、算法實現

Bellman-Ford算法在實現時,需要使用以下兩個數組。

(1)   使用同一個數組dist[n]來存放一系列的distk[n],其中k=1,2,...,n-1;算法結束時dist[u]數組中存放的是distn-1[u];

(2)   path[n]數組含義同Dijkstra算法中的path數組。

 

【例題1】利用Bellman-Ford算法求解下圖(a)中頂點0到其他各頂點的最短路徑長度,並輸出對應的最短路徑。

輸入:首先輸入頂點個數n,然後輸入每條邊的數據。每條邊的數據格式爲:u v w,分別表示這條邊的起點、終點和邊上的權值。頂點序號從0開始計起。最後一行爲-1 -1 -1,表示輸入數據的結束。

樣例輸入:                  樣例輸出:

7                                 1     0->3->2->1

0 1 6                            3     0->3->2

0 2 5                            5     0->3

0 3 5                            0     0->3->2->1->4

1 4 -1                           4     0->3->5

2 1 -2                           3     0->3->2->1->4->6

2 4 1

3 2 -2

3 5 -1

4 6 3

5 6 3

-1 -1 -1

 

【分析】

  如圖3(c)所示,k=1時,dist數組各元素的值dist[u]就是edge[0,u](見圖3(b))。在Bellman-Ford算法執行過程中,dist數組各元素的變化如圖3(c)所示。在圖3(c)中,dist[u]的值如有更新,則用粗體,紅色標明,u=1,2,3,4,5,6。以k=2,u=1加以解釋。求dist2[1]的遞推公式是:

dist2[1]=min{ dist1[1],min{dist1[j]+edge[j,1]}}   j=0,2,3,4,5,6

所以,在程序中k=2時,dist[1]的值爲:

 dist[1]=min{6,min{dist[0]+edge[0,1],dist[2]+edge[2,1], dist[3]+edge[3,1], dist[4]+edge[4,1],

dist[5]+edge[5,1], dist[6]+edge[6,1]}}

     =min{6,min{0+6, 5+(-2), 5+∞, ∞+∞, ∞+∞, ∞+∞}}

     =3

此時dist[1]的值爲從源點v0出發,經過不構成負權值迴路的兩條邊到達頂點v1的最短路徑長度,其路徑爲(v0,v2,v1)。

    在Bellman-Ford算法執行過程中,path[n]數組的變化與Dijkstra算法類似,所以在圖3中沒有列出path[n]數組的變化過程。當頂點0到其他各頂點的最短路徑長度求解完畢後,如果根據path數組求解頂點0到其他各頂點vk的最短路徑?方法跟Dijkstra算法中的方法完全一樣:從path[k]開始,採用“倒向追蹤”方法,一直找到源點v0。

在下面的代碼中,bellman(v0)函數實現了求源點v0到其他各頂點的最短路徑。在主函數中調用bellman(0),則求解的是從頂點0到其他各頂點的最短路徑。另外,主函數中的shortest數組用來保存最短路徑上各個頂點的序號,其作用和上一講中Dijkstra程序代碼中的shortest數組的作用一樣。

【參考程序】

var n:longint; //頂點個數
    i,j,k,u,v,w:longint;
    edge:array[0..8,0..8]of longint; //鄰接矩陣,這裏的8爲頂點個數最大值,可修改
    dist,path,shortest:array[0..8]of longint; //shortest數組是輸出最短路徑上的各個頂點時存放各個頂點的序號
procedure bellman(v0:longint);  //求頂點v0到其他頂點的最短路徑
  var i,j,k,u:longint;
  begin
    for i:=0 to n-1 do //初始化
      begin
        dist[i]:=edge[v0,i];
        if (i<>v0)and(dist[i]<1000000) then path[i]:=v0 else path[i]:=-1;
      end;
    for k:=2 to n-1 do //從dist(1)[u]遞推出dist(2)[u],...,dist(n-1)[u]
      begin
        for u:=0 to n-1 do //修改每個頂點的dist[u]和path[u]
          if u<>v0 then
              for j:=0 to n-1 do //考慮其他每個頂點
                if (edge[j,u]<1000000)and(dist[j]+edge[j,u]<dist[u]) then //頂點j到頂點u有直接路徑,且途經頂點j可以使得dist[u]縮短
                  begin
                    dist[u]:=dist[j]+edge[j,u];
                    path[u]:=j;
                  end;
      end;
  end;
begin
  readln(n); //讀入頂點個數
  while true do
    begin
      readln(u,v,w);   //讀入邊地起點,終點和權值
      if (u=-1)and(v=-1)and(w=-1) then break;
      edge[u,v]:=w; //構造鄰接矩陣
    end;
  for i:=0 to n-1 do  //設置鄰接矩陣中其他元素的值
    for j:=0 to n-1 do
      if i=j then edge[i,j]:=0
        else if edge[i,j]=0 then edge[i,j]:=1000000;
  bellman(0); //求頂點0到其他頂點的最短路徑
  for i:=1 to n-1 do
    begin
      write(dist[i],' ');  //輸出頂點0到頂點i的最短路徑長度
      //下面是輸出頂點0到頂點i的最短路徑
      fillchar(shortest,sizeof(shortest),0);
      k:=0; //k表示shortest數組中最後一個元素的下標
      shortest[k]:=i;
      while path[shortest[k]]<>0 do
        begin inc(k);shortest[k]:=path[shortest[k-1]];end;
      inc(k);shortest[k]:=0;
      for j:=k downto 1 do write(shortest[j],'->');
      writeln(shortest[0]);
   end;
end.



 

三、關於Bellman-Ford算法的進一步討論

1)本質思想

    在從dist(k-1)[]遞推到dist(k)[]的過程中,Bellman-Ford算法的本質是對每條邊<u,v>進行判斷:設邊<u,v>的權值爲w(u,v),如圖4所示,如果邊<u,v>的引入會使得dist(k-1)[v]的值再減小,則要修改dist(k-1)[v],即:如果dist(k-1)[u]+w(u,v)<dist(k-1)[v],則要講dist(k)[v]的值修改成dist(k-1)[u]+w(u,v)。這裏將修改dist(k-1)[v]的運算稱爲一次鬆弛(slack)。

 

按照這樣的思想,Bellman-Ford算法的遞推公式應該改爲(求源點v0到各頂點v的最短路徑):

初始:dist(0)[v]=∞,dist(0)[v0]=0,v0是源點,v<>v0

遞推:對每條邊(u,v),dist(k)[v]=min{dist(k-1)[v],dist(k-1)[u]+w(u,v)}  k=1,2,3,...,n-1

理解了這點,就能理解Bellman-Ford算法的複雜度分析、Bellman-Ford算法的優化等。

 

2)時間複雜度分析

在例題1的Bellman-Ford算法代碼中,有一個三重嵌套的for循環,如果使用鄰接矩陣存儲有向圖,最內層的if語句的總執行次數爲n^3,所以算法的時間複雜度爲o(n^3)。

如果使用鄰接表來存儲有向圖,內層的兩個for循環可以改成一個while循環,可以使算法的時間複雜度降爲o(n*m),其中n爲有向圖中頂點個數,m爲邊的數目。這時因爲,鄰接表裏直接存儲了邊地信息,瀏覽完所有的邊,複雜度爲o(m)。而鄰接矩陣是間接存儲邊,瀏覽完所有的邊,複雜度爲o(n^2)。

使用鄰接表存儲思想實現Bellman-Ford算法的具體過程爲:

將每條邊的信息(兩個頂點u,v和權值w,可以使用記錄record來實現)存儲到一個數組edges中,從dist(k-1)[]遞推到dist(k)[]的過程中,對edges數組中的每條邊<u,v>,判斷一下邊<u,v>的引入,是否會縮短源點v0到頂點v的最短路徑長度。

根據上面的分析,可以將例題1中的bellman函數簡化成如下代碼:

procedure bellman(v0:longint);  //求頂點v0到其他頂點的最短路徑
  vari,k:longint;
 begin
   for i:=0 to n-1 do //初始化dist數組
     begin dist[i]:=1000000;path[i]:=-1; end;
   dist[v0]:=0;
   for k:=1 to n-1 do //從dist(0)[u]遞推出dist(1)[u],...,dist(n-1)[u]
     //判斷第i條邊<u,v>的引入,是否會縮短源點v0到頂點v的最短路徑長度
       for i:=0 to m-1 do //m爲邊的數目,即edges數組中元素個數
         if(dist[edges[i].u]<.1000000)and(edges[i].w+dist[edges[i].u]<dist[edges[i].v])then
           begin
             dist[edges[i].v]:=edges[i].w+dist[edges[i,u];
              path[edges[i].v]:=edges[i].u;
            end;
 end;


  其中,dist數組各元素中,除源點v0外,其他頂點的dist[]值都初始化爲∞,這樣Bellman-Ford算法需要多遞推一次,詳見後面。

 

3Bellman-Ford算法負權值迴路的判斷方法

如果存在從源點可達的負權值迴路,則最短路徑不存在,因爲可以重複走這個迴路,使得路徑無窮小。在Bellman-Ford算法中,判斷是否存在從源點可達的負權值迴路的方法如下。在求出dist(n-1)[]後,再對每條邊<u,v>判斷一下:加入這條邊是否會使得頂點v的最短路徑值再縮短。即判斷:

dist[u]+edge[u,v]<dist[v]

是否成立,如果成立,則說明存在從源點可達的負權值迴路。代碼如下:

for i:=0 to n-1 do  //採用鄰接矩陣

  for j:=0 to n-1 do

    if (edge[i,j]<1000000)and(dist[i]+edge[i,j]<dist[j]) then exit(0);//存在從源點可達的負權值迴路

exit(1); //不存在從源點可達的負權值迴路  

 

或者:

for i:=0 to m-1 do

  if(dist[edges[i].u]<>1000000)and(edges[i].w+dist[edges[i].u]<dist[edges[i].v])then exit(0); //存在從源點可達的負權值迴路

exit(1); //不存在從源點可達的負權值迴路

 

4Bellman-Ford算法中數組dist的初始值

dist數組的初始值爲鄰接矩陣中源點v0所在的行,實際上還可以採用以下方式對dist數組初始化:除源點v0外,其他頂點的最短距離初始爲∞(在程序實現時可以用一個權值不會達到的一個大數表示):源點dist[v0]=0。這樣Bellman-Ford算法的第1重for循環要多執行一次,即要執行n-1次;且執行第1次後,dist數組的取值爲鄰接矩陣中源點v0所在的行。

 

5Bellman-Ford算法的改進

Bellman-Ford算法是否一定要循環n-2次,n爲頂點個數,即是否一定需要從dist(1)[u]遞推到dist(n-1)[u]?

答案是未必!其實只要在某次循環過程中,考慮每條邊後,都沒能改變當前源點到所有頂點的最短路徑長度,那麼Bellman-Ford算法就可以提前結束了。

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章