最短路徑問題
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[], intcollected[]) 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思想
設為從到的只以集合中的節點為中間節點的最短路徑的長度。
- 若最短路徑經過點k,則;
- 若最短路徑不經過點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)
最短路徑問題