<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
如果從圖中某一頂點(稱為源點)到達另一頂點(稱為終點)的路徑可能不止一條,如何找到一條路徑使得沿此路徑上各邊上的權值總和達到最小。
單源最短路徑問題是指對於給定的圖G=(V,E),求源點v0到其它頂點vt的最短路徑。
Dijkstra演演算法用於計算一個節點到其他節點的最短路徑。Dijkstra是一種按路徑長度遞增的順序逐步產生最短路徑的方法,是一種貪婪演演算法。
Dijkstra演演算法的核心思想是首先求出長度最短的一條最短路徑,再參照它求出長度次短的一條最短路徑,依次類推,直到從源點v0到其它各頂點的最短路徑全部求出為止。
具體來說:圖中所有頂點分成兩組,第一組是已確定最短路徑的頂點,初始只包含一個源點,記為集合S;第二組是尚未確定最短路徑的頂點,記為集合U。
按最短路徑長度遞增的順序逐個把U中的頂點加到S中去,同時動態更新U集合中源點到各個頂點的最短距離,直至所有頂點都包括到S中。
1.初始時,S集合只包含起點v0;U集合包含除v0外的其他頂點vt,且U中頂點的距離為起點v0到該頂點的距離。(U 中頂點vt的距離為(v0,vt)的長度,如果v0和vt不相鄰,則vt的最短距離為∞)
2.從U中選出距離最短的頂點vt′,並將頂點vt′加入到S中;同時,從U中移除頂點vt′。
3.更新U中各個頂點vt到起點v0的距離以及最短路徑中當前頂點的前驅頂點。之所以更新U中頂點的距離以及前驅頂點是由於上一步中確定了vt′是求出最短路徑的頂點,從而可以利用vt′來更新U中其它頂點vt的距離,因為存在(v0,vt)的距離可能大於(v0,vt')+(vt',vt)距離的情況,從而也需要更新其前驅頂點
4.重複步驟(2)和(3),直到遍歷完所有頂點
使用了部分C++11特性,註釋豐富,讀起來應該不會太困難!
#include <cstdio> #include <iostream> #include <vector> #include <list> #include <stack> using namespace std; using Matrix = vector<vector<uint>>; // 連線矩陣(使用巢狀的vector表示) using SNodes = vector<tuple<uint, uint, uint>>; // 已計算出最短路徑的頂點集合S(類似一個動態陣列) using UNodes = list<tuple<uint, uint, uint>>; // 未進行遍歷的頂點集合U(使用list主要是方便元素刪除操作) using ENode = tuple<uint, uint, uint>; // 每個節點包含(頂點編號,當前頂點到起始點最短距離,最短路徑中當前頂點的上一個頂點)資訊 /*** * 從未遍歷的U頂點集合中找到下一個離起始頂點距離最短的頂點 * @param unvisitedNodes 未遍歷的U頂點集合 * 每個元素是(頂點編號,當前頂點到起始點最短距離,最短路徑中當前頂點的上一個頂點)的tuple * @return 下一個離起始頂點距離最短的頂點 */ ENode searchNearest(const UNodes &unvisitedNodes) { uint minDistance = UINT_MAX; ENode nearest; for (const auto &node: unvisitedNodes) { if (get<1>(node) <= minDistance) { minDistance = get<1>(node); nearest = node; } } return nearest; } /*** * 迪克斯特拉演演算法的實現 * @param graph 連線矩陣(使用巢狀的vector表示) * @param startNodeIndex 起始點編碼(從0開始) * @return 返回一個vector,每個元素是到起始頂點的距離排列的包含(頂點編號,當前頂點到起始點最短距離,最短路徑中當前頂點的上一個頂點)的tuple */ SNodes dijkstra(const Matrix &graph, uint startNodeIndex) { const uint numOfNodes = graph.size(); // 圖中頂點的個數 // S是已計算出最短路徑的頂點的集合(頂點編號,當前頂點到起始點最短距離,最短路徑中當前頂點的上一個頂點) SNodes visitedNodes; // U是未計算出最短路徑的頂點的集合(其中的key為頂點編號,value為到起始頂點最短距離和最短路徑中上一個節點編號組成的pair) UNodes unvisitedNodes; // 對S和U集合進行初始化,起始頂點的距離為0,其他頂點的距離為無窮大 // 最短路徑中當前頂點的上一個頂點初始化為起始頂點,後面會逐步進行修正 for (auto i = 0; i < numOfNodes; ++i) { if (i == startNodeIndex) visitedNodes.emplace_back(i, 0, startNodeIndex); else unvisitedNodes.emplace_back(i, graph[startNodeIndex][i], startNodeIndex); } while (!unvisitedNodes.empty()) { // 從U中找到距離起始頂點距離最短的頂點,加入S,同時從U中刪除 auto nextNode = searchNearest(unvisitedNodes); unvisitedNodes.erase(find(unvisitedNodes.begin(), unvisitedNodes.end(), nextNode)); visitedNodes.emplace_back(nextNode); // 更新U集合中各個頂點的最短距離以及最短路徑中的上一個頂點 for (auto &node: unvisitedNodes) { // 更新的判斷依據就是起始頂點到當前頂點(nextNode)距離加上當前頂點到U集合中頂點的距離小於原來起始頂點到U集合中頂點的距離 // 更新最短距離的時候同時需要更新最短路徑中的上一個頂點為nextNode if (graph[get<0>(nextNode)][get<0>(node)] != UINT_MAX && graph[get<0>(nextNode)][get<0>(node)] + get<1>(nextNode) < get<1>(node)) { get<1>(node) = graph[get<0>(nextNode)][get<0>(node)] + get<1>(nextNode); get<2>(node) = get<0>(nextNode); } } } return visitedNodes; } /*** * 對使用迪克斯特拉演演算法求解的最短路徑進行列印輸出 * @param paths vector表示的最短路徑集合 * 每個元素是到起始頂點的距離排列的包含(頂點編號,當前頂點到起始點最短距離,最短路徑中當前頂點的上一個頂點)的tuple */ void print(const SNodes &paths) { stack<int> tracks; //從尾部出發,使用stack將每個頂點的最短路徑中的前一個頂點入棧,然後出棧的順序就是最短路徑順序 // 第一個元素是起始點,從第二個元素進行列印輸出 for (auto it = ++paths.begin(); it != paths.end(); ++it) { // 列印頭部資訊 printf("%c -> %c:t Length: %dt Paths: %c", char(get<0>(paths[0]) + 65), char(get<0>(*it) + 65), get<1>(*it), char(get<0>(paths[0]) + 65)); auto pointer = *it; // 如果當前指標pointer指向的節點有中途節點(判斷的條件是最短路徑中的前一個節點不是起始點) while (get<2>(pointer) != get<0>(paths[0])) { tracks.push(get<0>(pointer)); // Lambda表示式,使用find_if函數把當前頂點的前一個頂點從paths中找出來繼續進行迴圈直到前一個節點就是起始點 auto condition = [pointer](tuple<uint, uint, uint> x) { return get<0>(x) == get<2>(pointer); }; pointer = *find_if(paths.begin(), paths.end(), condition); } tracks.push(get<0>(pointer)); // 以出棧的順序進行列印輸出 while (!tracks.empty()) { printf(" -> %c", char(tracks.top() + 65)); tracks.pop(); } printf("n"); } } int main() { Matrix graph = { {0, 12, UINT_MAX, UINT_MAX, UINT_MAX, 16, 14}, {12, 0, 10, UINT_MAX, UINT_MAX, 7, UINT_MAX}, {UINT_MAX, 10, 0, 3, 5, 6, UINT_MAX}, {UINT_MAX, UINT_MAX, 3, 0, 4, UINT_MAX, UINT_MAX}, {UINT_MAX, UINT_MAX, 5, 4, 0, 2, 8}, {16, 7, 6, UINT_MAX, 2, 9, 9}, {14, UINT_MAX, UINT_MAX, UINT_MAX, 8, 9, 0} }; // 圖對應的連線矩陣 auto results = dijkstra(graph, uint('D' - 65)); // 選取頂點C(大寫字母A的ASCII編碼是65) print(results); // 列印輸出結果 return 0; }
執行結果:
D -> C: Length: 3 Paths: D -> C
D -> E: Length: 4 Paths: D -> E
D -> F: Length: 6 Paths: D -> E -> F
D -> G: Length: 12 Paths: D -> E -> G
D -> B: Length: 13 Paths: D -> C -> B
D -> A: Length: 22 Paths: D -> E -> F -> A
以上就是詳解Dijkstra演演算法原理及其C++實現的詳細內容,更多關於C++ Dijkstra演演算法的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45