【最短路徑問題】 如果將交通網路畫成帶權圖,結點代表地點,邊代表城鎮間的路,邊權表示路的長度, 則經常會遇到如下問題:兩給定地點間是否有通路?如果有多條通路,哪條路最短?還可以 根據實際情況給各個邊賦以不同含義的值。例如,對司機來說,里程和速度是他們最感興趣 的資訊;而對於旅客來說,可能更關心交通費用。有時,還需要考慮交通圖的有向性,如航行時,順水和逆水的情況。帶權圖的最短路徑是指兩點間的路徑中邊權和最小的路徑。
設有帶權的有向圖 d=(v,), d 中的邊權為 w(e)。已知源點為 v0,求 v0到其它各頂點的最短路徑。例如,在下圖所示的帶權有向圖中,v0為源點,則 v0到其他各頂點的最短路徑如表 7-3 所示,其中各最短路徑按路徑長度從小到大的順序排列。
下面介紹由迪傑斯特拉(dijkstra)提出的乙個演算法,來求解從頂點 v0出發到其餘頂點的最短路徑。該演算法按照最短路徑長度遞增的順序產生所有最短路徑。
對於圖 g=(v, e),將圖中的頂點分成兩組:
演算法將按最短路徑長度的遞增順序逐個將第二組的頂點加入到第一組中,直到所有頂點都被加入到第一組頂點集 s 為止。
[證明]:
可用反證法:假設下一條最短路徑上有乙個頂點 vy不在 s 中,即此路徑為(v0, …, vy, …, vx)。顯然,(v0,…,vy)的長度小於(v0,…,vy,… ,vx)的長度,故下一條最短路徑應 為(v0,…,vy),這與假設的下一條最短路徑(v0,…,vy,…, vx)相矛盾!因此,下一條 最短路徑上不可能有不在 s 中的頂點 vy,即假設不成立。
演算法中使用了輔助陣列 dist[ ], dist[i]表示目前已經找到的、從開始點 v0到終點 vi的當 前最短路徑的長度。它的初值為:如果從 v0到 vi 有弧,則 dist[i]為弧的權值;否則 dist[i]為 ∞。
根據上述定理,長度最短的一條最短路徑必為 ( v0, vk ),vk滿足如下條件:dist[k]=min
求得頂點 vk的最短路徑後,將 vk加入到第一組頂點集 s 中。
每加入乙個新的頂點 vk到頂點集 s,則對第二組剩餘的各個頂點而言,多了乙個「中轉」 結點,從而多了乙個「中轉」路徑,所以要對第二組剩餘的各個頂點的最短路徑長度 dist[i] 進行修正。
原來 v0到 vi 的最短路徑長度為 dist[i],加進 vk之後,以 vk作為中間頂點的「中轉」路 徑長度為:dist[k] + wki,( wki 為弧上的權值),若「中轉」路徑長度小於 dist[i],則將 頂點 vi的最短路徑長度修正為「中轉」路徑長度。
修正後,再選擇陣列 dist[ ]中值最小的頂點加入到第一組頂點集 s 中,如此進行下去, 直到圖中所有頂點都加入到第一組頂點集 s 中為止。
另外,為了記錄從 v0 出發到其餘各點的最短路徑(頂點序列),引進輔助陣列 path[ ],path[i]表示目前已經找到的、從開始點 v0 到終點 vi 的當前最短路徑頂點序列。它的初值為: 如果從 v0到 vi有弧,則 path[i]為(v0, vi);否則 path[i]為空。
【演算法思想】
g 為用鄰接矩陣表示的帶權圖。
【演算法描述】 圖的最短路徑演算法
#define infinity 32768
/*表示極大值,即∞*/
typedef
unsigned
int weighttype;
typedef weighttype adjtype;
typedef seqlist vertexset;
shortestpath_djs
(adjmatrix g,
int v0, weighttype dist[max_vertex_num]
, vertexset path[max_vertex_num]
)/* path[i]中存放頂點 i 的當前最短路徑。dist[i]中存放頂點 i 的當前最短路徑長度*/
}initlist
(&s)
;addtail
(&s, g.vertex[v0]);
/* 將 v0 看成第乙個已找到最短路徑的終點*/
for( t =
1; t<=g.vexnum-
1; t++
)/*求 v0 到其餘 n-1 個頂點的最短路徑(n= g.vexnum )*/
addtail
(&s, g.vertex[k]);
for( i =
0; i
)/*修正 dist[i], i∈v-s*/if(
!member
(g.vertex [i]
, s)
&& g.arcs[k]
[i].adj!= infinity &&
(dist[k]
+ g.arcs [k]
[i].adj
*/}}}
演算法前半部分完成了對向量最短路徑長度 dist[ ],路徑 path,頂點集 s的初始化工作。 演算法後半部分通過 n-1 次迴圈,將第二組頂點集 v-s 中的頂點按照遞增有序方式加入到集合 s 中,並求得從頂點 v0 出發到達圖中其餘頂點的最短路徑。
顯然,演算法的時間複雜度為 o(n²)
上述方法只能求出源點到其它頂點的最短路徑,欲求任意一對頂點間的最短路徑,可以 用每一頂點作為源點,重複呼叫狄傑斯特拉演算法 n 次,其時間複雜度為 o(n³)。下面介紹一 種形式更簡潔的方法,即佛羅伊德演算法,其時間複雜度也是 o(n³)。
【演算法思想】:
設圖 g 用鄰接矩陣法表示,求圖 g 中任意一對頂點 vi、、vj 間的的最短路徑。
圖 g 中所有頂點偶對 vi、vj間的最短路徑長度對應乙個 n 階方陣 d。在上述 n+1 步中, d 的值不斷變化,對應乙個 n 階方陣序列。
弗洛伊德演算法可以描述如下
【演算法描述】 弗洛伊德演算法
typedef seqlist vertexset;
shortestpath_floyd
(adjmatrix g, weighttype dist [max_vertex_num]
[max_vertex_num]
, vertexset path[max_vertex_num]
[max_vertex_num]
)/* g 為帶權有向圖的鄰接矩陣表示法, path [i][j]為 vi到 vj的當前最短路徑,dist[i][j]為 vi到 vj的當前最短路徑長度*/
}for
(k =
0;k)for
(i =
0;i)for
(j=0
;j(dist[i]
[k]+dist[k]
[j][j])
/* joinlist 是合併線性表操作 */
Codeup最短路徑 最短路徑
n個城市,標號從0到n 1,m條道路,第k條道路 k從0開始 的長度為2 k,求編號為0的城市到其他城市的最短距離。第一行兩個正整數n 2 n 100 m m 500 表示有n個城市,m條道路,接下來m行兩個整數,表示相連的兩個城市的編號。n 1行,表示0號城市到其他城市的最短路,如果無法到達,輸出...
Codeup最短路徑 最短路徑問題
給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。輸入n,m,點的編號是1 n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度為d,花費為p。最後一行是兩個數 s,t 起點s,...
最短路徑之最短路徑問題
提交 狀態 討論版 命題人 外部匯入 題目描述 平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中的一些點之間有連線。若有連線,則表示可從乙個點到達另乙個點,即兩點間有通路,通路的距離為兩點間的直線距離。現在的 任務是找出從一點到另一點之間的最短路徑。輸入共n m 3行,...