【高階數據結構(四)】圖的最短路徑問題

💓博主CSDN主頁:杭電碼農-NEO💓
?
?專欄分類:高階數據結構專欄?
?
🚚代碼倉庫:NEO的學習日記🚚
?
🌹關注我🫵帶你學習更多數據結構
? 🔝🔝


在這里插入圖片描述

高階數據結構

  • 1. 前言
  • 2. 單源最短路徑問題
  • 3. dijkstra算法講解
  • 4. bellman-Ford算法講解
  • 5. 多源最短路徑問題
  • 6. Floyd-Warshall算法講解
  • 7. 總結

1. 前言

關于圖論,無非就是最小生成樹問題和最短路徑問題. 對于最短路徑問題來說, 分為單源最短路徑和多源最短路徑, 并且圖中的權值是否有負數, 對應能使用的算法也不同

本章重點:

本篇文章著重講解圖的單源最短路徑之Dijkstra算法和bellman-Ford算法.以及多源最短路徑之Floyd-wars hall算法. 文章會著重講解這些算法的思路, 代碼實現部分要靠大家的理解能力了


2. 單源最短路徑問題

所謂的單源最短路徑,也就是從圖中任意一點出發, 到圖中每個節點的最短路徑,也就是最小的權值和

在這里插入圖片描述

對于單源最短路徑的求解. 我們一般使用輸出型參數. 用兩個數組來表示最短路徑的權值以及最短路徑的路徑.

//存儲任意點到圖中其他點的最短路徑的權值vector<W>& dist//記錄srci->其他頂點最短路徑父頂點數組vector<int>& parentPath

第一個數組很好理解. 圖中的頂點會簡化成為數組中的元素. 所以dist數組中的dist[i]=j.代表頂點i到srci的最短路徑的權值. 不好理解的是第二個數組. 它存儲的是最短路徑的父頂點. 什么意思呢? 請看下圖:

在這里插入圖片描述


3. dijkstra算法講解

針對一個帶權有向圖G,將所有結點分為兩組S和Q,S是已經確定最短路徑的結點集合,在初始時為空(初始時就可以將源節點s放入,畢竟源節點到自己的代價是0),Q 為其余未確定最短路徑的結點集合,每次從Q 中找出一個起點到該結點代價最小的結點u ,將u 從Q 中移出,并放入S 中,對u 的每一個相鄰結點v 進行松弛操作。

松弛即對每一個相鄰結點v ,判斷源節點s到結點u 的代價與u 到v 的代價之和是否比原來s 到v 的代價更小,若代價比原來小則要將s 到v 的代價更新為s 到u 與u 到v 的代價之和,否則維持原樣。如此一直循環直至集合Q 為空,即所有節點都已經查找過一遍并確定了最短路徑,至于一些起點到達不了的結點在算法循環后其代價仍為初始設定的值,不發生變化

定義很抽象,現在來看看實圖:

在這里插入圖片描述

從S開始,s->y是最短路徑了, 就以y為起點(y的值被更新為5)更新與y相連的t,z,x. 同時s->t也被更新為10. y->t小于s->t. 所以將t重新更新為8. x,z也是同理. 第二次更新完. s->z最短.就以z為起點更新與z相連的x.以此類推.直到所有頂點都在集合S中.

話不多說,上代碼:

void Dijkstra(const V& src, vector<W>& dist, vector<int>& pPath)//Dijkstra算法求解最短路徑,兩個數組,一個存儲兩個點之間的最小權值(從src點,到圖中其他的點),另一個存父路徑節點下標
{size_t srci = GetIndex(src);size_t n = _vertex.size();dist.resize(n, MAX_W);pPath.resize(n, -1);dist[srci] = W();pPath[srci] = srci;vector<bool> check(n, false);//此數組中存放已經確定了的最短路勁的節點for(int j=0;j<n;j++)//n個節點,一共會更新n次,也可以判斷check數組中的元素是否全為true{//選最短路徑的頂點更新其他路徑(不在s中)int u = 0;//最小的點的下標W minu = MAX_W;//最小的點的權值for (int i = 0; i < n; i++)//選擇dist數組中權值最小的,作為起始點來進行松弛操作{if (check[i] == false && dist[i] < minu){u = i;minu = dist[i];check[i] = true;}}//進行松弛更新,srci->u, u->其他頂點(v), srci->v就可以更新出來for (int v = 0; v < n; v++)//從0到n,把與u點相連的所有頂點都找出來更新{if (_edge[u][v] != MAX_W && dist[u] + _edge[u][v] < dist[v])//若srci->u+u->v的距離小于dist[v]的大小,則更新他{dist[v] = dist[u] + _edge[u][v];pPath[v] = u;}}}
}

此算法只適用于不帶負權路徑的圖
若有不懂,歡迎私信


4. bellman-Ford算法講解

Dijkstra算法只適用于不帶負權路徑的圖, 具體的原因可以參考這篇文章: 負權路徑帶來的后果

顯而易見, bellman算法可以解決帶負權路徑的圖

說白了此算法就是一個暴力求解的過程, 它的時間復雜度是O(N^3). 它的思路就是以所有頂點為起始點,更新所有相連的邊

在這里插入圖片描述

更新次序就是(t,z),(t,y),(t,z),(y,x),(y,z), (z,x), (z,s), (s,t), (s,y). 更新(y,z)時,由于更新后的值是7+9=16>2,所以不會更新這條邊. 其他更新邊也是同理. 但是這樣暴力更新一次并不能解決問題,因為假如只更新一次, (s,t)的值就是6, 但是顯而易見, s->y->x->t的權值是2,要小于6. 出現這種情況的原因是, 還沒有以x為起始點進行更新其他點時, 根本就不知道x->t這條路. 所以我們需要以所有點為起始點更新n次,n是頂點的數量

上代碼:

bool BellmanFord(const V& src, vector<W>& dist, vector<int>& pPath)//貝爾曼-福特算法求解最短路徑
{size_t srci = GetIndex(src);size_t n = _vertex.size();dist.resize(n, MAX_W);pPath.resize(n, -1);dist[srci] = W();//用i->j,圖中的所有邊去更新for (int k = 0; k < n; k++)//再套一層循環的原因是,只更新一輪可能會有問題,更新K輪一定不會有問題{bool check = false;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (_edge[i][j] != MAX_W && dist[i] + _edge[i][j] < dist[j])//若這條邊存在,并且從i->j要少于直接0->j{dist[j] = dist[i] + _edge[i][j];pPath[j] = i;check = true;}}}if (check == true) breal;}//有可能K輪循環后,會形成閉環return true;
}

很明顯它的時間復雜度是O(N^3)


5. 多源最短路徑問題

說白了就是任意兩點之間的最短路徑
Floyd-Warshall算法就是解決方法之一

和單源最短路徑算法的思路相似. 這里需要用到兩個數組, 只不過這里是用兩個二維數組, 一個二維數組存儲頂點i->j的最短路徑值, 另外一個數組存儲 (i,j)的父節點下標. i,j是最短路徑的中間某節點


6. Floyd-Warshall算法講解

Floyd算法考慮的是一條最短路徑的中間節點,即簡單路徑p={v1,v2,…,vn}上除v1和vn的任意節
點。設k是p的一個中間節點,那么從i到j的最短路徑p就被分成i到k和k到j的兩段最短路徑p1,p2。p1是從i到k且中間節點屬于{1,2,…,k-1}取得的一條最短路徑。p2是從k到j且中間節點屬于{1,2,…,k-1}取得的一條最短路徑

在這里插入圖片描述

在這里插入圖片描述

你可能覺得很抽象,下面來個實際案例:

在這里插入圖片描述
在這里插入圖片描述

上代碼:

void FloydWarShall(vector<vector<W>>& vvDist, vector<vector<int>>& vvpPath)//多源最短路徑求解問題(任意兩點的最短路徑),數組vvDist中包含了所有點的最短距離
{size_t N = _vertex.size();vvDist.resize(N);vvpPath.resize(N);for (int i = 0; i < N; i++){vvDist[i].resize(N, MAX_W);vvpPath[i].resize(N, -1);}//把直接相連的邊給更新一下,后續就不需要_edge數組了for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){if (_edge[i][j] != MAX_W)//直接相連{vvDist[i][j] = _edge[i][j];vvpPath[i][j] = i;//起點是i,目前的父路徑暫時是i(后面可能會是K)}if (i == j)vvDist[i][j] = W();}}//最短路徑的更新,i->j,中間可能經過了k個頂點,i->{其他頂點(最多是N-2)}->j//k作為i,j的中間點,k可以是任意頂點,k可以是1,2,3,任意點,要把所有點拿來更新for (int k = 0; k < N; k++)//雖然是最多只需要走n-2個點,但是這里除掉的兩個點我們并不知道是哪兩個,所以都需要走一遍{for (int i = 0; i < N; i++){for (int j = 0; j < N; j++){//以K作為中間的去更新i->j的路徑if (vvDist[i][k] != MAX_W && vvDist[k][j] != MAX_W && vvDist[i][k] + vvDist[k][j] < vvDist[i][j])//i->k的路徑和k->j的路徑都存在,并且i->k加上k->j的路徑小于i直接到j{vvDist[i][j] = vvDist[i][k] + vvDist[k][j];vvpPath[i][j] = vvpPath[k][j];//這里j的父路徑不能直接寫成k,因為k->j中間可能還有其他點,比如k->x->y->j,最開始的i,j是在_edge數組中取得,而這里應該是從vvppath[k][j]中取得,需要找跟j相連的上一個頂點}}}}
}

7. 總結

圖論總體來說比較抽象,很難理解這些算法的思路. 但是也不用慌張,圖論本身就屬于加分項, 你知道算法原理即可, 不用會手撕, 換個角度, 面試官也不一定能手撕這些算法.


🔎 下期預告:LRU cache講解 🔍

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/13347.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/13347.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/13347.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第八篇 Asciidoc 輸出 All In One HTML 解決圖片無法顯示問題

問題:我的圖片顯示不出來了 小明使用 Asciidoc 來記筆記,他將筆記輸出為 HTML 文件。小麗向小明借筆記。小明將 Asciidoc 筆記輸出為 HTML文件,并拷貝給了小麗。 但是,小麗發現,圖片都顯示不出來了。 小麗:小明,你給我的筆記,圖片都顯示不出來啊。 小明:是我給你的…

析構函數詳解

目錄 析構函數概念特性對象的銷毀順序 感謝各位大佬對我的支持,如果我的文章對你有用,歡迎點擊以下鏈接 &#x1f412;&#x1f412;&#x1f412; 個人主頁 &#x1f978;&#x1f978;&#x1f978; C語言 &#x1f43f;?&#x1f43f;?&#x1f43f;? C語言例題 &…

yolov8實戰之 .pt 轉. tensorRT

1 yolo 訓練 1.1修改自己的數據集合 我是有3個類別&#xff0c;差不多這么些數據 1.2 訓練 from ultralytics import YOLO # Load a model model YOLO("yolov8m.yaml") # build a new model from scratch #model YOLO(E:/pythonCode/pythonProject1/runs/detec…

風電功率預測 | 基于PSO-BP神經網絡實現風電功率預測(附matlab完整源碼)

風電功率預測 風電功率預測完整代碼風電功率預測 基于粒子群優化算法(Particle Swarm Optimization, PSO)的BP神經網絡是一種常見的方法,用于實現風電功率預測。下面是一個基于PSO-BP神經網絡實現風電功率預測的一般步驟: 數據準備:收集與風電場發電功率相關的數據,包括…

農林科學SCI期刊,IF=6+,影響力高,對國人非常友好!

一、期刊名稱 Crop Journal 二、期刊簡介概況 期刊類型&#xff1a;SCI 學科領域&#xff1a;農林科學 影響因子&#xff1a;6.6 中科院分區&#xff1a;1區 出版方式&#xff1a;開放出版 版面費&#xff1a;$900 三、期刊征稿范圍 《作物雜志》是一份雙月刊、國際、同…

PHP使用Browsershot進行網頁截圖

Browsershot是什么 Spatie Browsershot 是一個開源PHP庫&#xff0c;它允許開發者在PHP應用程序中生成網頁的截圖。 這個庫特別適用于Laravel框架&#xff0c;但也可以在其他 PHP 應用程序中使用。 主要特點 無頭瀏覽器截圖&#xff1a;使用無頭版本的 Chrome 或 Chromium 瀏…

整理好了!2024年最常見 100 道 Java基礎面試題(四十九)

上一篇地址&#xff1a;整理好了&#xff01;2024年最常見 100 道 Java基礎面試題&#xff08;四十八&#xff09;-CSDN博客 九十七、Class.forName 和 ClassLoader 的區別&#xff1f; Class.forName 和 ClassLoader 是Java中用于加載類的兩個不同的概念&#xff0c;它們在類…

10W 3KVAC隔離 寬電壓輸入 AC/DC 電源模塊 ——TP10AF系列

TP10AF系列輸出功率為10W&#xff0c;具有可靠性高、更小的體積、性價比高等特點&#xff0c;廣泛用于工控和電力儀器、儀表、智能家居等相關行業。

SMB攻擊利用之-mimikatz上傳/下載流量數據包逆向分析

SMB協議作為windows環境下最為常見的一種協議,在歷史上出現過無數的通過SMB協議進行網絡攻擊利用的案例,包括針對SMB協議本身以及通過SMB協議實施網絡攻擊。 本文將介紹一種通過SMB協議的常見利用方式,即向遠程主機傳輸mimikatz,作為我的專欄《SMB攻擊流量數據包分析》中的…

Oracle數據塊之數據行中的SCN

從Oracle 10g開始&#xff0c;如果在表級別打開ROW DEPENDENCIES&#xff0c;業務數據行發生更改時會在數據塊中進行登記。 可以通過DUMP數據塊來觀察上述SCN&#xff1a; &#xff08;1&#xff09;創建測試表&#xff0c;插入3條測試數據&#xff0c;插入一條提交一次。并調用…

解析建筑裝飾乙級資質標準及申請流程

建筑裝飾乙級資質標準 資歷與信譽 必須具備獨立的企業法人資格。社會信譽良好&#xff0c;注冊資本不少于100萬元人民幣。 技術條件 專業技術人員配備齊全、合理&#xff0c;滿足相應資質標準中對主要專業技術人員數量和專業的具體要求。通常包括但不限于室內設計、建筑、環境藝…

jar包增量更新分析

jdk自帶工具jdeps&#xff0c;可分析class依賴關系&#xff08;依賴的其它類和jar&#xff09;。 團隊&#xff0c;可以在此工具結果的基礎上再詳細分析對比出增量文件&#xff1b; 思路如下&#xff1a; jdeps分別分析出舊包和新包的文件依賴關系。并對比出新增的文件列表、…

前端學習第一課

AJAX 事先說明&#xff0c;這只是記錄&#xff0c;并不是從零到一的教學內容&#xff0c;如果想要學習的話&#xff0c;可以跳過本文章了 ok&#xff0c;轉回正題&#xff0c;正如上面所說&#xff0c;這只是記錄。其實我是有一定的前端基礎的&#xff0c;也做過涉及相關的開發…

【工具】macOS、window11訪問limux共享目錄\共享磁盤,samba服務安裝使用

一、samba服務安裝 Samba是一個免費的開源軟件實現&#xff0c;使得非Windows操作系統能夠與Windows系統進行文件和打印服務共享。它實現了SMB/CIFS協議&#xff0c;并且能夠在Linux、Unix、BSD等多種系統上運行。 安裝 samba&#xff1a; sudo yum install samba配置 samba…

【kali工具】NMAP 高級使用技巧

NMAP 高級使用技巧 6.1.3 NMAP 語法及示例 語法&#xff1a;nmap [Scan Type(s)] [Options] 例 1&#xff1a;使用 nmap 掃描一臺服務器 默認情況下&#xff0c;Nmap 會掃描 1000 個最有可能開放的 TCP 端口。 ┌──(root&#x1f480;xuegod53)-[~] └─# nmap 192.168…

【介紹下Python多線程,什么是Python多線程】

&#x1f308;個人主頁: 程序員不想敲代碼啊 &#x1f3c6;CSDN優質創作者&#xff0c;CSDN實力新星&#xff0c;CSDN博客專家 &#x1f44d;點贊?評論?收藏 &#x1f91d;希望本文對您有所裨益&#xff0c;如有不足之處&#xff0c;歡迎在評論區提出指正&#xff0c;讓我們共…

【氣象常用】時間序列的線性擬合

效果圖&#xff1a; 主要步驟&#xff1a; 1. 數據準備&#xff1a;下載Hadley Centre observations datasets的HadSST數據 可參考【氣象常用】時間序列圖-CSDN博客 2. 數據處理&#xff1a;計算線性擬合 3. 圖像繪制&#xff1a;繪制折線及擬合線&#xff0c;并添加文本 …

Nacos部署選擇數據源mysql8.0,啟動報錯No DataSource Set(終極解決方案)

Nacos部署選擇數據源mysql8.0&#xff0c;啟動報錯No DataSource Set&#xff08;終極解決方案&#xff09; 選擇mysql5.7正常&#xff0c;但是選擇mysql8.0就報這個錯&#xff0c;配置都確認無問題&#xff0c;但就是用不了mysql8.0 排查了好久&#xff0c;發現是數據庫字符集…

其他自動化工程師都在偷偷學習AI技術,你再不學就落后了!一篇文章教會你使用AI!

其他自動化工程師都在偷偷學習AI技術&#xff0c;你再不學就落后了&#xff01;一篇文章教會你使用AI&#xff01; 哈嘍&#xff0c;大家好&#xff0c;我是小叔。了解小叔的朋友都清楚&#xff0c;我從來都不是標題黨&#xff0c;我只會用美女圖片來吸引你們&#x1f602;&am…

python 六句話讓電腦告訴你,剛才插入的串口編號

六句話讓電腦告訴你&#xff0c;我的串口號 第一步&#xff0c;安裝python 編譯器以及pyserial 模塊第二步&#xff0c;寫入代碼 import serial.tools.list_ports usart_list list(serial.tools.list_ports.comports()) input("Please insert your serial port:")…