图的最短路径--单源、多源最短路径
最短路徑
–在網絡中,求兩個不同頂點之間的所有路徑中,邊的權值之和最小的路勁。
單源最短路徑
–從某固定源點出發的最短路徑
無權圖的最短路徑
- 按照路徑長度遞增的順序找出源點到各個頂點的最短路徑
-
類似于BFS-寬度優先遍歷,可以通過隊列來實現,
- 先讓頂點入隊,循環執行下列步驟
- 出隊首元素,訪問其所有鄰接點
- 標明源點到這些鄰接點的路徑長度,并將其入隊
有權圖的最短路徑
Dijkstra算法
-
令第一組為集合S={源點+已經確定最短路徑的頂點vi}
-
令第二組為未在集合S中的頂點v,定義length成員為源點s到v的最短路徑長度,該路徑除了終點v以外,所有頂點都必須是集合S中的頂點。即{s—>(vi∈S)—>v}的最小長度
-
每次對未在第一組集合S的頂點,選一個length最小的頂點(記為v),將其增加至集合S中。
-
如何選這個頂點V–用一個最小堆H(剛開始只有源點),每次找出并刪除一個length值最小的頂點V,這里這個找到并刪除的頂點V就是每次加入集合S的頂點,然后找到V的所有鄰接點,對其鄰接點的length值進行賦值,然后加入最小堆H里,往復循環,直至最小堆空了(最小堆空了,即所有頂點都加入了集合S)–看程序就明白了
-
選進去的時候要注意什么–增加v進集合S中會影響頂點w(w為v的鄰接點)的length值,因為多了個頂點v,可能會改變s—w的走法,原先不經過v,現在最短路徑經過v,即需要考慮
length[w],與length[v] + e.weigth的大小關系--------(1)
-
-
直到把所有頂點都送進集合S中
設源點為V0,則按照Dijkstra算法的最短路徑求解過程如下
注:初始的時候只有集合S只有源點s,因此只有到點v1、v2有路徑,路徑長度用length表示,,沒有路徑則length為∞,路徑的終點的前一個點用pre表示。
```C++ class Dist { // Dist類,用于保存最短路徑信息public:int index; // 結點的索引值int length; // 當前最短路徑長度int pre; // 路徑最后經過的結點 };void Dijkstra(Graph& G, int s, Dist* &D) { // s是源點D = new Dist[G. VerticesNum()]; // 開辟空間給類Dist,用來記錄當前最短路徑長度for (int i = 0; i < G.VerticesNum(); i++) { // 初始化,將圖中所有頂點的標志位記為未訪問,將Dist類的索引值記為頂點號,將頂點到源點的length置為∞。G.Mark[i] = UNVISITED; D[i].index = i; D[i].length = INFINITE;D[i].pre = s;}D[s].length = 0; // 初始化,源點自身的路徑長度置為0MinHeap<Dist> H(G. EdgesNum()); // 最小堆用于找出集合S中到源點的路徑最短的點,最小堆存放Dist類元素,共有G.EdgesNum個長度H.Insert(D[s]); //將源點放入最小堆for (i = 0; i < G.VerticesNum(); i++) {bool FOUND = false;Dist d;while (!H.isEmpty()) {d = H.RemoveMin(); //獲得集合S中到源點s路徑長度最小的結點,并刪除if (G.Mark[d.index] == UNVISITED) { //如果未訪問過則跳出循環FOUND = true; break;} }if (!FOUND) break; // 若沒有符合條件的最短路徑則跳出本次循環int v = d.index; G.Mark[v] = VISITED; // 將標記位設置為 VISITEDfor (Edge e = G.FirstEdge(v); G.IsEdge(e); e = G.NextEdge(e)) // 對最小堆中到源點路徑最短的頂點v,求他的每個鄰接點,并考慮是否需要改變其最小距離--刷新最短路,然后將其加入最小堆if (D[G.ToVertex(e)].length > (D[v].length+G.Weight(e))) {//這里第一次執行時,因為剛開始最小堆里只有源點,其他頂點到源點的length都為∞,執行完后V1、V2的length值才改變D[G.ToVertex(e)].length = D[v].length + G.Weight(e);D[G.ToVertex(e)].pre = v;H.Insert(D[G.ToVertex(e)]);} } }Dijkstra算法時間復雜度
T = O ( ∣ V ∣ l o g ∣ V ∣ + ∣ E ∣ l o g ∣ V ∣ ) = O ( ∣ E ∣ l o g ∣ V ∣ ) T = O( |V| log|V| + |E| log|V| ) = O( |E| log|V| ) T=O(∣V∣log∣V∣+∣E∣log∣V∣)=O(∣E∣log∣V∣)
前半部分為在最小堆里找V次,依次復雜度為logV,后半部分是往最小堆里插入Dist,一次最多有可能插E次(極限情況,一個頂點有E條邊)
Dijkstra使用條件
- 圖中不能出現有總權值為負值的回路
- 如果存在負值邊也有可能發生計算錯誤
- 持負權值的最短路徑算法有Ford算法、SPFA算法
多源最短路徑
–求每對頂點間的最短路徑
Floyd算法
-
Dk[i] [j]表示路徑{ i —> { l<= k } —> j }的最小長度(i、j、l、k表示頂點編號)
-
首先用矩陣D0表示該圖的鄰接矩陣
-
在矩陣D0上做n次迭代
-
如何迭代呢–當Dk-1已經完成,遞推到Dk時,
-
若k?最短路徑{ i —> { l<= k } —> j },(即i到j的最短路徑不經過k)則Dk=Dk-1
-
若k∈最短路徑{ i —> { l<= k } —> j }(即i到j的最短路徑經過k),則該最短路徑由兩條路徑組成:
D ( k ) [ i ] [ j ] = D ( k ? 1 ) [ i ] [ k ] + D ( k ? 1 ) [ k ] [ j ] D(k)[i][j]=D(k-1)[i][k]+D(k-1)[k][j] D(k)[i][j]=D(k?1)[i][k]+D(k?1)[k][j]
-
Floyd算法時間復雜度
T = O ( ∣ V ∣ 3 ) T = O( |V|3 ) T=O(∣V∣3)
總結
以上是生活随笔為你收集整理的图的最短路径--单源、多源最短路径的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 酒店客房管理系统之系统实施--数据库
- 下一篇: 【计算机组成原理】一、基本运算器实验