圖的應用——最短路徑

這是我參與8月更文挑戰的第13天,活動詳情查看:8月更文挑戰算法

最短路徑

  • 典型用途:交通問題。如:城市A到城市B有多條線路,但每條線路的交通費(或所需時間)不一樣,那麼,如何選擇一條線路,使總費用(或總時間)最少?
  • 問題抽象:在帶權有向圖中A點(源點)到達B點(終點)的多條路徑中,尋找一條各邊權值之和最小的路徑,即最短路徑。

最短路徑與最小生成樹不一樣,路徑上不必定包含n個頂點markdown

兩種常見最短路徑問題


Dijkstra(迪傑斯特拉)算法 —— 單源最短路徑

在這裏插入圖片描述

算法思想

把圖中頂點集合分紅兩組:post

第一組爲已求出其最短路徑的頂點集合S 第二組爲還沒有肯定最短路徑的頂點集合Uspa

  1. 初始時,S只包含源點,S={v},U包含除v外的其餘頂點;
  2. 從U中選取一個距離最小的頂點k,把k加入到S中;
  3. 以k做爲新考慮的中間點,修改U中各頂點的距離;
  4. 重複步驟 二、3 直到全部頂點都包含在S中

算法實現

算法流程圖 在這裏插入圖片描述 C++代碼實現code

void ShortestPath_DIJ(AMGraph G, int v0){
	// 用Dijkstra算法求有向網G的v0頂點到其他頂點的最短路徑 
	n = G.vexnum;  // G 中頂點個數
	for(v = 0; v < n; v++){
		// n 個頂點依次初始化
		S[v] = false;  // S 初始爲空集
		D[v] = G.arcs[v0][v];  // 將v0到各個終點的最短路徑長度初始化 
		if(D[v] < MaxInt) Path[v] = v0;  // v0和v之間有弧,將v的前驅置爲v0
		else Path[v] = -1;  // 若是v0和v之間無弧,則將v的前驅置爲-1
	}
	S[v0] = true;  // 將v0加入S
	D[v0] = 0;  // 源點到源點的距離爲0

	/*―開始主循環,每次求得v0到某個頂點v的最短路徑,將v加到S集―*/
	for(i = 1; i < n; i++){
		// 對其他n-1個頂點,依次進行計算
		min = MaxInt;
		for(w = 0; w < n; w++)
			if(!S[w] && (D[w] < min)){
				v = w;
				min = D[w];  // 選擇一條當前的最短路徑,終點爲v
			}
		S[v] = true;  // 將v加入S
		for(w = 0; w < n; w++)  // 更新從v0出發到集合V−S上全部頂點的最短路徑長度
			if(!S[w] && ((D[v] + G.arcs[v][w]) < D[w])){
				D[w] = D[v] + G.arcs[v][w];  // 更新D[w]
				Path[w] = v;  // 更新w的前驅爲v
			}
	}
}
複製代碼

Floyd(弗洛伊德)算法 —— 全部頂點間的最短路徑

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

方法一:每次以一個頂點爲源點,重複執行Dijkstra算法n次—— T(n)=O(n³) 方法二:弗洛伊德(Floyd)算法 算法思想:逐個頂點試探法圖片

算法思想

  • 初始時設置一個n階方陣,令其對角線元素爲0,若存在弧<Vi,Vj>,則對應元素爲權值;不然爲∞
  • 逐步試着在原直接路徑中增長中間頂點,若加入中間點後路徑變短,則修改之;不然,維持原值。
  • 全部頂點試探完畢,算法結結束

在這裏插入圖片描述

算法實現

typedef int Pathmatirx[MAXVEX][MAXVEX]
typedef int ShortPathTable[MAXVEX][MAXVEX]

/*- Floyd算法,求網圖G中各頂點v到其他頂點w最短路徑P[v][w]及帶權長度D[v][w] -*/
void ShrotestPath_Floyd(MGraph G, Pathmatirx* P, ShortPathTable* D){
	int v, w, k;
	for(v = 0; v < G.numVertexes; ++v){
		// 初始化D與P
		for(w = 0; w < G.numVertexes; ++w){
			(*D)[v][w] = G.matirx[v][w];  // D[v][w]值即爲對應點間的權值
			(*P)[v][w] = w;  // 初始化P

		}
	}

	for(k = 0; k < G.numVertexes; ++k)
		for(v = 0; v < G.numVertexes; ++v)
			for(w = 0; w < G.numVertexes; ++w)
				if((*D)[v][w] > (*D)[v][k] + (*D)[k][w]){
					// 若是通過下標爲k頂點路徑比原兩點間路徑更短
					// 將當前兩點間權值設爲更小的一個
					(*D)[v][w] = (*D)[v][k] + (*D)[k][w];
					(*P)[v][w] = (*P)[v][k];  // 路徑設置爲通過下標爲k的頂點
				}
}
複製代碼
相關文章
相關標籤/搜索