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++)也許有的人會有疑問,這樣的遍歷只遍歷了中間點個數為1的情況,沒有考慮中間點個數大於等於1的情況。其實不然,在計算中間點為k的最小值的時候,把能更新的元素都更新了,比如說更新了e[i][j],這時候矩陣中第i行第j列的元素實際上是e[i][k]+e[k][j],而不是e[i][j]了。這邊用到了動態規劃的思想。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];
演算法核心:每次引入乙個點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行,...