最短路徑問題

2022-06-07 03:42:10 字數 3511 閱讀 6118

floyed演算法(時間複雜度為o(n3),空間複雜度為o(n2)),是解決任意兩點間的最短路徑的一種演算法,可以正確處理有向圖負權的最短路徑問題。

暑假,小哼準備去一些城市旅遊。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節省經費以及方便計畫旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。

上圖中有4個城市8條公路,公路上的數字表示這條公路的長短。請注意這些公路是單向的。我們現在需要求任意兩個城市之間的最短路程,也就是求任意兩個點之間的最短路徑。這個問題這也被稱為「多源最短路徑」問題。

我們可以用乙個4*4的矩陣(二維陣列e)來儲存圖的資訊。比如:

具體如下

如果要讓任意兩點(例如從頂點a點到頂點b)之間的路程變短,只能引入第三個點(頂點k),並通過這個頂點k中轉即a->k->b,才可能縮短原來從頂點a點到頂點b的路程。當然這個中轉的頂點有時候甚至不止乙個,即a->k1->k2b->或者a->k1->k2…->k->i…->b。比如上圖中從4號城市到3號城市(4->3)的路程e[4][3]原本是12。如果只通過1號城市中轉(4->1->3),路程將縮短為11(e[4][1]+e[1][3]=5+6=11)。其實1號城市到3號城市也可以通過2號城市中轉,使得1號到3號城市的路程縮短為5(e[1][2]+e[2][3]=2+3=5)。所以如果同時經過1號和2號兩個城市中轉的話,從4號城市到3號城市的路程會進一步縮短為10。

因此,我們可以遍歷每乙個點作為中間點k,然後計算最小值

for (k = 1; k <= n; k++)

for (i = 1; i <= n; i++)

for (j = 1; j <= n; j++)

if (e[i][j] > e[i][k] +e[k][j])

e[i][j] = e[i][k] + e[k][j];

也許有的人會有疑問,這樣的遍歷只遍歷了中間點個數為1的情況,沒有考慮中間點個數大於等於1的情況。其實不然,在計算中間點為k的最小值的時候,把能更新的元素都更新了,比如說更新了e[i][j],這時候矩陣中第i行第j列的元素實際上是e[i][k]+e[k][j],而不是e[i][j]了。這邊用到了動態規劃的思想。

演算法核心:每次引入乙個點k來更新i到j最短距離,求出任意兩點之間的最短距離。

基本步驟如下:

從任意一條單邊路徑開始,所有兩點之間的距離是邊的權,如果兩點之間沒有邊相連,則權為無窮大。

對於每一對頂點u和v,看看是否存在乙個頂點w使得從u到w再到v比己知的路徑更短,如果是更新它。

對於所有的頂點,都重複上面的操作,直到遍歷所有的頂點。

用於計算乙個節點到其他節點的最短路徑。 

它的主要特點是以起始點為中心向外層層擴充套件(廣度優先搜尋思想),直到擴充套件到終點為止

通過dijkstra計算圖g中的最短路徑時,需要指定起點s(即從頂點s開始計算)。

此外,引進兩個集合s和u。s的作用是記錄已求出最短路徑的頂點(以及相應的最短路徑長度),而u則是記錄還未求出最短路徑的頂點(以及該頂點到起點s的距離)。

初始時,s中只有起點s;u中是除s之外的頂點,並且u中頂點的路徑是」起點s到該頂點的路徑」。然後,從u中找出路徑最短的頂點,並將其加入到s中;接著,更新u中的頂點和頂點對應的路徑。 然後,再從u中找出路徑最短的頂點,並將其加入到s中;接著,更新u中的頂點和頂點對應的路徑。 … 重複該操作,直到遍歷完所有頂點。

初始狀態:s是已計算出最短路徑的頂點集合,u是未計算除最短路徑的頂點的集合!

第1步:將頂點d加入到s中。 

此時,s=, u=。 注:c(3)表示c到起點d的距離是3。

第2步:將頂點c加入到s中。 

上一步操作之後,u中頂點c到起點d的距離最短;因此,將c加入到s中,同時更新u中頂點的距離。以頂點f為例,之前f到d的距離為∞;但是將c加入到s之後,f到d的距離為9=(f,c)+(c,d)。 

此時,s=, u=。

第3步:將頂點e加入到s中。 

上一步操作之後,u中頂點e到起點d的距離最短;因此,將e加入到s中,同時更新u中頂點的距離。還是以頂點f為例,之前f到d的距離為9;但是將e加入到s之後,f到d的距離為6=(f,e)+(e,d)。 

此時,s=, u=。

第4步:將頂點f加入到s中。 

此時,s=, u=。

第5步:將頂點g加入到s中。 

此時,s=, u=。

第6步:將頂點b加入到s中。 

此時,s=, u=。

第7步:將頂點a加入到s中。 

此時,s=。

此時,起點d到各個頂點的最短距離就計算出來了:a(22) b(13) c(3) d(0) e(4) f(6) g(12)。

/*

* dijkstra最短路徑。

* 即,統計圖(g)中"頂點vs"到其它各個頂點的最短路徑。

* * 引數說明:

* g -- 圖

* vs -- 起始頂點(start vertex)。即計算"頂點vs"到其它頂點的最短路徑。

* prev -- 前驅頂點陣列。即,prev[i]的值是"頂點vs"到"頂點i"的最短路徑所經歷的全部頂點中,位於"頂點i"之前的那個頂點。

* dist -- 長度陣列。即,dist[i]是"頂點vs"到"頂點i"的最短路徑的長度。 */

void dijkstra(graph g, int vs, int prev, int

dist)

//對"頂點vs"自身進行初始化

flag[vs] = 1

; dist[vs] = 0

;

//遍歷g.vexnum-1次;每次找出乙個頂點的最短路徑。

for (i = 1; i < g.vexnum; i++)

}//標記"頂點k"為已經獲取到最短路徑

flag[k] = 1

;

//修正當前最短路徑和前驅頂點

//即,當已經"頂點k的最短路徑"之後,更新"未獲取最短路徑的頂點的最短路徑和前驅頂點"。

for (j = 0; j < g.vexnum; j++)}}

//列印dijkstra最短路徑的結果

printf("

dijkstra(%c): \n

", g.vexs[vs]);

for (i = 0; i < g.vexnum; i++)

printf(

"shortest(%c, %c)=%d\n

", g.vexs[vs], g.vexs[i], dist[i]);

}

最短路 最短路徑問題

題目描述 平面上有n個點 n 100 每個點的座標均在 10000 10000之間。其中的一些點之間有連線。若有連線,則表示可從乙個點到達另乙個點,即兩點間有通路,通路的距離為兩點直線的距離。現在的任務是找出從一點到另一點之間的最短路徑。input 共有n m 3行,其中 第一行為乙個整數n。第2行...

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行,...