最短路徑算法


一、單源點最短路徑問題 :

問題描述:給定帶權有向圖G=(V, E)和源點v∈V,求從v到G中其余各頂點的最短路徑。

迪傑斯特拉(Dijkstra)提出了一個按路徑長度遞增的次序產生最短路徑的算法。

Dijkstra算法

基本思想:設置一個集合S存放已經找到最短路徑的頂點,S的初始狀態只包含源點v,對vi∈V-S,假設從源點v到vi的有向邊為最短路徑。以后每求得一條最短路徑v, …, vk,就將vk加入集合S中,並將路徑v, …, vk , vi與原來的假設相比較,取路徑長度較小者為最短路徑。重復上述過程,直到集合V中全部頂點加入到集合S中。

  下一條最短路徑(設其終點為vi)或者是弧(v0,vi),或者是中間經過S中的頂點而最后到達頂點vi的路徑。

  

示例

算法步驟:

① 令S={Vs} ,用帶權的鄰接矩陣表示有向圖,對圖中每個頂點Vi按以下原則置初值:

② 選擇一個頂點Vj ,使得:dist[j]=Min{ dist[k]| Vk∈V-S },Vj就是求得的下一條最短路徑終點,將Vj 並入到S中,即S=S∪{Vj} 。

③ 對V-S中的每個頂點Vk ,修改dist[k],方法是:

  若dist[j]+Wjk<dist[k],則修改為:dist[k]=dist[j]+Wjk ("Vk∈V-S )

④ 重復②,③,直到S=V為止。

算法實現

 1 void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D)
 2 
 3 { 
 4 
 5     // 用Dijkstra算法求有向網G的v0頂點到其余頂點v的最短路徑P[v]
 6 
 7     // 及其帶權長度D[v]。
 8 
 9     // 若P[v][w]為TRUE,則w是從v0到v當前求得最短路徑上的頂點。
10 
11     // final[v]為TRUE當且僅當v∈S,即已經求得從v0到v的最短路徑。
12 
13     int i=0,j, v,w,min;
14 
15     bool final[MAX_VERTEX_NUM];
16 
17     for (v=0; v<G.vexnum; ++v) 
18 
19     {
20 
21         final[v] = FALSE;  
22 
23         D[v] = G.arcs[v0][v].adj;
24 
25         for (w=0; w<G.vexnum; ++w)  
26 
27             P[v][w] = FALSE;  // 設空路徑
28 
29         if (D[v] < INFINITY) { P[v][v0] = TRUE;  P[v][v] = TRUE; }
30 
31     }
32 
33     D[v0] = 0;  final[v0] = TRUE;        // 初始化,v0頂點屬於S集
34 
35     //--- 開始主循環,每次求得v0到某個v頂點的最短路徑,並加v到S集 ---
36 
37     for (i=1; i<G.vexnum; ++i)          // 其余G.vexnum-1個頂點
38 
39     {         
40 
41         min = INFINITY;                    // 當前所知離v0頂點的最近距離
42 
43         for (w=0; w<G.vexnum; ++w)
44 
45             if (!final[w])                           // w頂點在V-S中
46 
47                 if (D[w]<min) { v = w;  min = D[w]; }  // w頂點離v0頂點更近
48 
49         final[v] = TRUE;                       // 離v0頂點最近的v加入S集
50 
51         for (w=0; w<G.vexnum; ++w)             // 更新當前最短路徑及距離
52 
53             if (!final[w] && (min+G.arcs[v][w].adj<D[w])) 
54 
55             { 
56 
57                 // 修改D[w]和P[w], w∈V-S
58 
59                 D[w] = min + G.arcs[v][w];
60 
61                 P[w] = P[v];P[w][w] = TRUE; //P[w] = P[v]+[w]  
62 
63             }
64 
65     }
66 
67 }

 

 

二、每一對頂點之間的最短路徑

問題描述:給定帶權有向圖G=(V, E),對任意頂點vi,vj∈V(i≠j),求頂點vi到頂點vj的最短路徑。

  解決辦法1:每次以一個頂點為源點,調用Dijkstra算法n次。顯然,時間復雜度為O(n3)。

  解決辦法2:弗洛伊德提出的求每一對頂點之間的最短路徑算法——Floyd算法,其時間復雜度也是O(n3),但形式上要簡單些。

Floyd算法

基本思想:對於從vivj的弧,進行n次試探:首先考慮路徑vi,v0,vj是否存在,如果存在,則比較vi,vjvi,v0,vj的路徑長度,取較短者為從vivj的中間頂點的序號不大於0的最短路徑。在路徑上再增加一個頂點v1,依此類推,在經過n次比較后,最后求得的必是從頂點vi到頂點vj的最短路徑。

示例

數據結構

圖的存儲結構:帶權的鄰接矩陣存儲結構  

數組dist[n][n]:存放在迭代過程中求得的最短路徑長度。迭代公式: 

數組path[n][n]:存放從vi到vj的最短路徑,初始為path[i][j]="vivj"。

算法實現

 1 void ShortestPath_FLOYD(MGraph G, PathMatrix P[], DistancMatrix &D) 
 2 
 3 {
 4 
 5     // 用Floyd算法求有向網G中各對頂點v和w之間的最短路徑P[v][w]及其
 6 
 7     // 帶權長度D[v][w]。若P[v][w][u]為TRUE,則u是從v到w當前求得最
 8 
 9     // 短路徑上的頂點。
10 
11     int v,w,u,i;
12 
13     for (v=0; v<G.vexnum; ++v)        // 各對結點之間初始已知路徑及距離
14 
15         for (w=0; w<G.vexnum; ++w) 
16 
17         {
18 
19             D[v][w] = G.arcs[v][w].adj;
20 
21             for (u=0; u<G.vexnum; ++u) P[v][w][u] = FALSE;
22 
23             if (D[v][w] < INFINITY) 
24 
25             {    
26 
27                 // 從v到w有直接路徑
28 
29                 P[v][w][v] = P[v][w][w] = TRUE;
30 
31             }
32 
33         }
34 
35     for (u=0; u<G.vexnum; ++u)
36 
37         for (v=0; v<G.vexnum; ++v)
38 
39             for (w=0; w<G.vexnum; ++w)
40 
41                 if (D[v][u]+D[u][w] < D[v][w]) 
42 
43                 {  
44 
45                     // 從v經u到w的一條路徑更短
46 
47                     D[v][w] = D[v][u]+D[u][w];
48 
49                     for (i=0; i<G.vexnum; ++i)
50 
51                         P[v][w][i] =(P[v][u][i] || P[u][w][i]);
52 
53                 }
54 
55 }

注:本文來自http://www.cnblogs.com/navorse/articles/1894297.html

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM