1. 程式人生 > >最短路徑問題

最短路徑問題

調用 ini 順序 lba turn init als 所有 lin

Dijkstra算法:有權圖的單源最短路

技術分享

1.最短路必定只經過S中的頂點

  如果還存在一個w在S之外,v0>w必定小於v0>v,但路徑是按照遞增順序生成的,那麽w一定已經收錄了,與前提矛盾。

2.新收錄一個v,會影響v的鄰接點的dist值

  如果收錄v使得s>w的路徑變短,則s>w的路徑一定經過v,並且v>w有一條邊。如果v>w中間還存在頂點的話,該頂點一定在S之外(S是按遞增順序生成的,v剛被收錄)而w的dist值為只經過S中的頂點。 dist[w] = min{dist[w], dist[v]+ <v, w>的權重}

3.過程

  1.從V-S中找到dist[i]最小的下標i,收錄到S中

  2.更新與i的鄰接點的dist值 

  3.V==S時停止

4.代碼

 1 //鄰接矩陣存儲
 2 #define MaxVertexNum 1100
 3 struct GraphNode
 4 {
 5     int Nv;
 6     int Ne;
 7     int G[MaxVertexNum][MaxVertexNum];
 8 };
 9 typedef struct GraphNode *MGraph;
10 
11 Vertex FindMinDist(MGraph Graph, int dist[], int
collected[]) 12 { 13 Vertex MinV, V; 14 int MinDist = INFINITY; 15 16 for (V = 0; V < Graph->Nv; V++) { 17 if (collected[V] == false && dist[V]<MinDist) //在未收錄中找且dist[V]更小 18 { 19 MinDist = dist[V]; 20 MinV = V; 21 } 22 }
23 if (MinDist < INFINITY) 24 return MinV; 25 else 26 return ERROR; 27 } 28 29 bool Dijkstra(MGraph Graph, int dist[], int path[], Vertex s) 30 { 31 int collected[MaxVertexNum]; 32 Vertex v, w; 33 34 for (v = 0; v < Graph->Nv; v++) { 35 dist[v] = Graph->G[s][v]; 36 if (dist[v] < INFINITY) 37 path[v] = s; 38 else 39 path[v] = -1; 40 collected[v] = false; 41 } 42 dist[v] = 0; 43 collected[s] = true; 44 45 while (1) { 46 v = FindMinDist(Graph, dist, collected); 47 if (v == ERROR) 48 break; //全收錄完 49 collected[v] = true; 50 for (w = 0; w < Graph->Nv; w++) { 51 if (collected[w] == false && Graph->G[v][w]<INFINITY) { 52 if (Graph->G[v][w] < 0) //負值圈 53 return false; 54 if (dist[v]+Graph->G[v][w] < dist[w]) { 55 dist[w] = dist[v] + Graph->G[v][w]; 56 path[w] = v; 57 } 58 } 59 } 60 } 61 return true; 62 }

5.時間復雜度

  直接掃描所有未收錄的頂點 T = O(|V|^2 + |E|) 稠密圖效果好

  若用最小堆存取dist 讀取最小的並更新堆O(log|V|), 但更新dist[w]的值需要插入最小堆O(log|V|) T = O(|V|log|V| + |E|log|V|) = O(|E|log|V|) 稀疏圖較好 (E和V同一個數量級,|V|log|V|比|V|^2要好)

若將單源最短路算法調用|V|遍,對於稠密圖T = O(|V|^3 + |E||V|) 對於稀疏圖較好

對於稠密圖有Floyd算法 

Floyd算法:多源最短路算法

采用DP思想

技術分享為從技術分享技術分享的只以技術分享集合中的節點為中間節點的最短路徑的長度。

  1. 若最短路徑經過點k,則技術分享
  2. 若最短路徑不經過點k,則技術分享

因此,技術分享

 1 //鄰接矩陣存儲
 2 
 3 bool Floyd(MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[])
 4 {
 5     Vertex i, j, k;
 6     
 7     for (i = 0; i < Graph->Nv; i++)
 8     for (j = 0; j < Graph->Nv; j++) {
 9         D[i][j] = Graph->G[i][j];
10         path[i][j] = -1;
11     }
12     
13     for (k = 0; k < Graph->Nv; k++)
14         for (i = 0; i < Graph->Nv; i++)
15             for (j = 0; j < Graph->Nv; j++)
16                 if (D[i][k] + D[k][j] < D[i][j]) 
17                 {
18                     D[i][j] = D[i][k] + D[k][j];
19                     if (i == j && D[i][j] < 0)
20                         return false;
21                     path[i][j] = k;
22                 }
23     return true;
24 }

輸出路徑:

  遞歸輸出, 先輸出i到k,再輸出k,再輸出k到j路線。

時間復雜度

  T = O(|V|^3)

最短路徑問題