利用Dijkstra演算法實現記錄每個結點的所有最短路徑
最近在做PAT時發現圖論的一些題目需要對多條最短路徑進行篩選,一個直接的解決辦法是在發現最短路徑的時候就進行判斷,選出是否更換路徑;另一個通用的方法是先把所有的最短路徑記錄下來,然後逐個判斷。前者具有一定的難度並且不好排查BUG,因此我設計了一種基於Dijkstra的記錄所有最短路的簡捷演算法,用於解決此類題目。
我們知道,Dijkstra是解決單源最短路問題的,並且最基本的演算法僅能求出最短路的長度,而不能輸出路徑,本文基於Dinjkstra進行改進,使之能記錄源點到任意點的所有最短路徑。
使用vector<int>來記錄一條路徑,因為每個結點可能有多條最短路徑,因此把這些路徑都裝在一個vector中,因此可以用一個vector<vector<int> >來表示一個結點的所有最短路徑,把所有結點的最短路徑都存放起來,又需要一個vector容器,因此所有結點的所有最短路徑的集合可以用vector<vector<vector<int> > >來表示。
約定:結點編號為0到N-1,源點為0,到每個點的最短距離儲存在陣列minD[N]中。
在Dijkstra演算法初始化時,找出所有源點的鄰接點w並且把相應的最短距離minD[w]更新,同時初始化這些點w的第一條最短路徑0->w(實現方法為分別push_back 0和w)。接下來將會找到一個到源點最短的點v,並且把v併入集合,對v的所有未訪問的鄰接點,如果到達w的路徑(0->...->w)在包含v之後(0->...->v->w)變短,則刪除w之前所有的最短路徑,並且更新為到v的所有最短路徑加上w點(注意對每個到v的最短路徑都要這樣處理);如果到達w的路徑在包含v之後長度不變,說明發現了一條新的最短路徑,在w原來最短路徑容器的基礎上再壓入一個新的最短路徑,這條路徑為所有到v的最短路徑加上w點。
經過這樣的運算,就可以得到所有結點的所有最短路徑了,下面以一個例項對演算法進行測試,並且附上原始碼。
題目:求下圖的源點0到所有結點的最短路徑。
輸入:
5 8
2 4 1
0 1 3
0 2 6
1 3 2
1 4 1
3 4 1
3 2 1
0 4 4
輸出:
原始碼為:
#include <iostream> #include <stdio.h> #include <vector> using namespace std; #define MAX 1001 #define INF 99999999 int G[MAX][MAX]; int minD[MAX]; int minDist; int finalSet[MAX]; int main() { int N,M; int v1,v2; int len; cin >> N >> M; for(int i = 0; i < N; i++){ finalSet[i] = 0; minD[i] = INF; for(int j = 0; j < N; j++) G[i][j] = INF; } for(int i = 0; i < M; i++){ scanf("%d%d%d",&v1,&v2,&len); G[v1][v2] = G[v2][v1] = len; } vector<vector<vector<int> > > nodes(N); // 設0為源點,計算從0到所有點的所有最短路徑 finalSet[0] = 1; minD[0] = 0; // 首先把所有源點鄰接點的最短距離初始化為源點到這些點的距離 for(int i = 1; i < N; i++){ if(G[0][i] != INF) { minD[i] = G[0][i]; vector<vector<int> > minPaths; minPaths.clear(); vector<int> pathList; pathList.clear(); pathList.push_back(0); pathList.push_back(i); minPaths.push_back(pathList); nodes[i] = minPaths; } } // 從所有minD中找出最小的,併入集合S,重複N-1次(源點已經加入集合) for(int i = 1; i < N; i++){ minDist = INF; int v = -1; // 記錄到源點記錄最小的結點 for(int w = 1; w < N; w++){ if(!finalSet[w] && minDist > minD[w]){ minDist = minD[w]; v = w; } } if(v == -1) break; // v = -1說明找不到點了,當圖不連通時才會出現這種情況 // 已經找到了到源點最近的點v,將其併入集合,並且考慮原來的最短距離0->...->W在加入了v之後有沒有可能變短 // 如果變短了,就更新為0->...>v->W finalSet[v] = 1; for(int w = 1; w < N; w++){ if(!finalSet[w]){ int newD = minDist + G[v][w]; if(newD < minD[w]){ minD[w] = newD; vector<vector<int> > minPathsV = nodes[v]; vector<int> pathList; nodes[w].clear(); for(int index = 0; index < minPathsV.size(); index++){ pathList = minPathsV[index]; pathList.push_back(w); nodes[w].push_back(pathList); } }else if(newD == minD[w]){ vector<vector<int> > minPathsV = nodes[v]; vector<int> pathList; for(int index = 0; index < minPathsV.size(); index++){ pathList = minPathsV[index]; pathList.push_back(w); nodes[w].push_back(pathList); } } } } } for(int i = 1; i < N; i++){ cout << "------------" << endl; cout << "0 to "<< i << ":" << endl; cout << "The miniest distance:" << endl << minD[i] << endl; cout << "The possible paths:" << endl; vector<vector<int> >minPaths = nodes[i]; int size = minPaths.size(); vector<int> pathList; for(int j = 0; j < size; j++){ pathList = minPaths[j]; int pathSize = pathList.size(); for(int k = 0; k < pathSize - 1; k++){ cout << pathList[k] << "->"; } cout << pathList[pathSize - 1] << endl; } } return 0; }
相關推薦
利用Dijkstra演算法實現記錄每個結點的所有最短路徑
最近在做PAT時發現圖論的一些題目需要對多條最短路徑進行篩選,一個直接的解決辦法是在發現最短路徑的時候就進行判斷,選出是否更換路徑;另一個通用的方法是先把所有的最短路徑記錄下來,然後逐個判斷。前者具有一定的難度並且不好排查BUG,因此我設計了一種基於Dijkstra的記錄所
Dijkstra演算法(有權圖單源最短路徑)
從一個源點到其他各頂點的最短路徑問題稱為“單源最短路徑問題”。 最短路徑的最優子結構性質 該性質描述為:如果P(i,j)={Vi…Vk…Vs…Vj}是從頂點i到j的最短路徑,k和s是這條路徑上的一箇中間頂點,那麼P(k,s)必定是從k
Dijkstra演算法,有權單源最短路徑
與無權單源最短路徑相似,與層次遍歷相似;以遞增的順序依次收錄遇到的最短距離的頂點 int findmin(Graph G,int dist[],int collected[]) // 找到一個未被收錄的最小值 { int Min = MAXNUM; // 儲存最小值,初值為無窮大;
Dijkstra演算法--一個點到其餘點最短路徑
Dijkstra演算法 要求 求一個點(源點)到其餘各個頂點的最短路徑。 思路 先將源點到其餘各個點的路徑列出來dis[],找到最小值,這個最小值就是源點到這一點u的最短路徑,並標記已經找出,再以這個點開始,依次遍歷到其它點v,如果這個點u到
用Dijkstra演算法求解無向圖的最短路徑
Dijkstra演算法是典型的演算法。Dijkstra演算法是很有代表性的演算法。Dijkstra一般的表述通常有兩種方式,一種用永久和臨時標號方式,一種是用OPEN, CLOSE表的方式,這裡均採用永久和臨時標號的方式。注意該演算法要求圖中不存在負權邊。
Dijkstra演算法實現==2014hiho第23周最短路問題
小Ho想了想說道:“唔……我覺得動態規劃可以做,但是我找不到計算的順序,如果我用f[i]表示從S到達編號為i的節點的最短距離的話,我並不能夠知道f[1]..f[N]的計算順序。” “所以這個問題不需要那麼複雜的演算法啦,我就稍微講講你就知道了!”小Hi道:“路的長度不可能為負數對不對?” “那是自然,畢竟人
迪傑斯特拉演算法處理無向圖中最短路徑的(dijkstra)Java實現(指定兩點,求最短距離及路徑)
其實不是原創哈,我寫不出來。 如何求圖中V0到V5的最短路徑呢? java實現的方式如下: 第一步,根據圖來建立權值矩陣: int[][] W = { { 0, 1, 4, -1, -
結點對最短路徑之Floyd演算法原理詳解及實現
上兩篇部落格介紹了計算單源最短路徑的Bellman-Ford演算法和Dijkstra演算法。Bellman-Ford演算法適用於任何有向圖,即使圖中包含負環路,它還能報告此問題。Dijkstra演算法執行速度比Bellman-Ford演算法要快,但是其要求圖中不能包含負權重
結點對最短路徑Floyd弗洛伊德演算法解析
暑假,小哼準備去一些城市旅遊。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節省經費以及方便計劃旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。 上圖中有4個城市8條公路,公路上的數字表示這條公路的長短。請注意這些公
貪心演算法之用優先佇列解決最短路徑問題(Dijkstra演算法)
#include <iostream> #include <cstdio> #include <stack> #include <cstring> #include <queue> #include <cstdlib> using na
【資料結構與演算法】 有向圖的最短路徑實現
Goal: Practice the algorithms of shortest pathproblem. Task:用一個有向圖表示給定的n個(要求至少10個)城市(或校園中的一些地點)及其之間的道路、距離情況,道路是有方向的。要求完成功能:根據使用者輸入的任意兩個城
每對結點之間最短路徑的C++實現
轉載本部落格上原創文章者,請註明出處。 Dijkstra演算法和Bellman-Ford演算法只能計算出起始點到其他各點的最短路徑,但不能計算任意兩隊頂點之間的最短路徑。若真想利用這兩張演算法,可以來一個迴圈,每次讓不同的頂點成為起始頂點,這樣也可以解決,但這種方法效率比較
資料結構實驗34——求賦權圖中一個結點到所有結點的最短路徑的長度
Description給一個賦權圖(無向圖),求0號結點到其餘所有結點的最短路徑的長度。Input先輸入一個小於等於100的正整數n,然後輸入賦權圖的鄰接矩陣(10000表示無窮大,並且任意一條簡單路徑
設計一個演算法,輸出從u到v的所有最短路徑(採用鄰接表儲存)
思想:用path陣列存放路徑(初始為空),d表示路徑長度(初始為-1),查詢從頂點u到v的最短路徑過程如圖所示: 對應演算法如下: void FindPath(
Flody演算法(有權多源最短路徑問題)
多源最短路徑問題,即為求每一對頂點之間的最短路徑問題 演算法描述 演算法思想原理: Floyd演算法是一個經典的動態規劃演算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。從動態規劃的
hdu2066 dijkstra多源點多終點求最短路徑
dijkstra演算法的思路: (1)找到最短距離已經確定的頂點,從它出發更新相鄰頂點的最短距離 (2)此後不再關心(1)中最短距離已經確定的頂點 最開始時只有起點的最短距離是確定的,而在未使用過的頂點中,距離d[i]最小的頂點就是最短距離已經確定的頂點,在不存在負邊的情況下d[i]不會
hdu2066 dijkstra多源點多終點求最短路徑
dijkstra演算法的思路: (1)找到最短距離已經確定的頂點,從它出發更新相鄰頂點的最短距離 (2)此後不再關心(1)中最短距離已經確定的頂點 最開始時只有起點的最短距離是確定的,而在未使用過的頂點中,距離d[i]最小的頂點就是最短距離已經確定的頂點,在不存在負邊的
求無向圖頂點之間的所有最短路徑
思路一: DFS,遇到終點之後進行記錄 輔助儲存: std::vector<int> tempPath; std::vector<std::vector<int>> totalPath; 實現: //查詢無向
簡單圖論:遍歷所有最短路徑
今天遇到了兩道要求遍歷所有最短路徑的題,我一直做不對的原因竟是我把無向圖當成了有向圖,鬱悶的要死。 解決遍歷所有最短路徑,其實思路很簡單,首先通過經典演算法[各種演算法,Dijkstra,bellman,floyd]求出最短路徑的長度,然後就只能DFS來找尋起始點、終點一樣
floyd演算法(求任意兩點間的最短路徑)
floyd演算法用於求任意兩點間的最短路徑,時間複雜度為O(n^3)。 通過多次呼叫 Digkstar 演算法同樣能解決這個問題,時間複雜度同樣為O(n^3),但floyd更簡潔,利於程式設計。 fl