代碼隨想錄算法訓練營第60期第六十三天打卡

? ? ? ? 大家好,我們昨天講解的是拓撲排序與Dijkstra算法的樸素版,其實我們大致了解了兩種算法的代碼實現,我們通過上次博客了解到拓撲排序其實是可以判斷圖里是否存在環,而Dijkstra算法則使用于非負邊權最短路的求解,今天我們繼續昨天的內容,我們首先要了解的就是Djikstra算法的堆優化版本,這個其實我以前就了解過這個算法,還有一個就是Bellman_ford 算法,這個其實就彌補了Djikstra算法不能求解帶負邊權的最短路,那么很明顯我們今天的主題就是最短路算法了。

第一部分 dijkstra(堆優化版)

? ? ? ? 這個我們首先要區分我們上次講過的樸素版,我們就來看看這個算法是如何實現的?其實關于圖的存儲方式我們以前就有講解過主要有兩種方法,一種是鄰接矩陣法還有一種是鄰接表法,我們說鄰接表法對于稀疏圖的存儲,只需要存儲邊,空間利用率高,遍歷節點鏈接情況相對容易,這里我們就使用鄰接表來存儲圖,第一步:選源點到哪個節點近且該節點未被訪問過,第二步:該最近節點被標記訪問過,第三步:更新非訪問節點到源點的距離(即更新minDist數組),其實我們在前面的樸素版的dijkstra算法就有提到過這個三部曲,但在那個版本的算法里這三部曲是套在一個 for 循環里,為什么?因為我們是從節點的角度來解決問題。那么當從 邊 的角度出發, 在處理 三部曲里的第一步(選源點到哪個節點近且該節點未被訪問過)的時候 ,我們可以不用去遍歷所有節點了。而且 直接把 邊(帶權值)加入到 小頂堆(利用堆來自動排序),那么每次我們從 堆頂里 取出 邊 自然就是 距離源點最近的節點所在的邊。這個思路我感覺是非常妙,堆是一種很常用的數據結構,它具備排序的功能,當然可能有的語言默認大根堆,有的默認小根堆,我們這里要使用小根堆,因為我們要尋找的是最短路徑,這樣我們就不需要兩層for循環來尋找最近的節點了。

? ? ? ?這樣有了大致的思路以后,我們就可以逐漸嘗試去寫代碼,但是代碼一開始我們就遇到了麻煩,我們應該如何表示鄰接表呢?在vector<list<int>> grid(n + 1);?中 就不能使用int了,而是需要一個鍵值對 來存兩個數字,一個數表示節點,一個數表示 指向該節點的這條邊的權值。我們的堆優化版依舊是我們的三部曲,那么三部曲中的第一步(選源點到哪個節點近且該節點未被訪問過),我們如何選?我們要選擇距離源點近的節點(即:該邊的權值最小),所以 我們需要一個 小頂堆 來幫我們對邊的權值排序,每次從小頂堆堆頂 取邊就是權值最小的邊。這個寫起C++代碼來也是很難,后面我會一并給出,接下來的更新過程與我們以前是類似的,我就不多說了,我們直接給出大家代碼:

#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <climits>
using namespace std; 
// 小頂堆
class mycomparison {
public:bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {return lhs.second > rhs.second;}
};
// 定義一個結構體來表示帶權重的邊
struct Edge {int to;  // 鄰接頂點int val; // 邊的權重Edge(int t, int w): to(t), val(w) {}  // 構造函數
};int main() {int n, m, p1, p2, val;cin >> n >> m;vector<list<Edge>> grid(n + 1);for(int i = 0; i < m; i++){cin >> p1 >> p2 >> val; // p1 指向 p2,權值為 valgrid[p1].push_back(Edge(p2, val));}int start = 1;  // 起點int end = n;    // 終點// 存儲從源點到每個節點的最短距離std::vector<int> minDist(n + 1, INT_MAX);// 記錄頂點是否被訪問過std::vector<bool> visited(n + 1, false); // 優先隊列中存放 pair<節點,源點到該節點的權值>priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pq;// 初始化隊列,源點到源點的距離為0,所以初始為0pq.push(pair<int, int>(start, 0)); minDist[start] = 0;  // 起始點到自身的距離為0while (!pq.empty()) {// 1. 第一步,選源點到哪個節點近且該節點未被訪問過 (通過優先級隊列來實現)// <節點, 源點到該節點的距離>pair<int, int> cur = pq.top(); pq.pop();if (visited[cur.first]) continue;// 2. 第二步,該最近節點被標記訪問過visited[cur.first] = true;// 3. 第三步,更新非訪問節點到源點的距離(即更新minDist數組)for (Edge edge : grid[cur.first]) { // 遍歷 cur指向的節點,cur指向的節點為 edge// cur指向的節點edge.to,這條邊的權值為 edge.valif (!visited[edge.to] && minDist[cur.first] + edge.val < minDist[edge.to]) { // 更新minDistminDist[edge.to] = minDist[cur.first] + edge.val;pq.push(pair<int, int>(edge.to, minDist[edge.to]));}}}if (minDist[end] == INT_MAX) cout << -1 << endl; // 不能到達終點else cout << minDist[end] << endl; // 到達終點最短路徑
}

? ? ?這里定義小頂堆要注意,還要注意我們的pair表示的是什么。

第二部分 Bellman_ford 算法

? ? ? ?Bellman_ford算法的核心思想是 對所有邊進行松弛n-1次操作(n為節點數量),從而求得目標最短路,這個相當重要,這個松弛是什么意思,這里可以這樣理解:

? ? ? ? minDist[B] 表示 到達B節點 最小權值,minDist[B] 有哪些狀態可以推出來?狀態一: minDist[A] + value 可以推出 minDist[B] 狀態二: minDist[B]本身就有權值 (可能是其他邊鏈接的節點B 例如節點C,以至于 minDist[B]記錄了其他邊到minDist[B]的權值),這樣的話minDist[B] 應為如何取舍。本題我們要求最小權值,那么 這兩個狀態我們就取最小的,也就是說,如果 通過 A 到 B 這條邊可以獲得更短的到達B節點的路徑,即如果?minDist[B] > minDist[A] + value,那么我們就更新?minDist[B] = minDist[A] + value?,這個過程就叫做 “松弛” 。這個其實不就還是更新最短路徑,這個是不是讓大家想起我們以前學過的動態規劃,動態規劃里面不就經常有取最小值的操作。接下來我可以簡單給大家模擬一下松弛的操作:首先對所有邊松弛一次,相當于計算 起點到達 與起點一條邊相連的節點 的最短距離

?

? ? ? ??大家可以先看一下上面的圖,邊:節點1 -> 節點2,權值為1 ,minDist[2] > minDist[1] + 1 ,更新 minDist[2] = minDist[1] + 1 = 0 + 1 = 1 ,接下來邊:節點2 -> 節點5,權值為2 ,minDist[5] > minDist[2] + 2 (經過上面的計算minDist[2]已經不是默認值,而是 1),更新 minDist[5] = minDist[2] + 2 = 1 + 2 = 3 ,但是節點5 -> 節點3,權值為1 ,minDist[5] 還是默認數值max,所以不能基于節點5去更新節點3 ,后續的都是這樣,我就不給大家一一演示了。

? ? ? 最后我們可以嘗試給出完整代碼:

#include <iostream>
#include <vector>
#include <list>
#include <climits>
using namespace std;int main() {int n, m, p1, p2, val;cin >> n >> m;vector<vector<int>> grid;// 將所有邊保存起來for(int i = 0; i < m; i++){cin >> p1 >> p2 >> val;// p1 指向 p2,權值為 valgrid.push_back({p1, p2, val});}int start = 1;  // 起點int end = n;    // 終點vector<int> minDist(n + 1 , INT_MAX);minDist[start] = 0;for (int i = 1; i < n; i++) { // 對所有邊 松弛 n-1 次for (vector<int> &side : grid) { // 每一次松弛,都是對所有邊進行松弛int from = side[0]; // 邊的出發點int to = side[1]; // 邊的到達點int price = side[2]; // 邊的權值// 松弛操作 // minDist[from] != INT_MAX 防止從未計算過的節點出發if (minDist[from] != INT_MAX && minDist[to] > minDist[from] + price) { minDist[to] = minDist[from] + price;  }}}if (minDist[end] == INT_MAX) cout << "unconnected" << endl; // 不能到達終點else cout << minDist[end] << endl; // 到達終點最短路徑}

? ? ? ? ?這就是我們的Bellman_ford算法,大家一刷稍微有一些了解就可以,暫時不必追根究底。

今日總結

? ? ? ? ?今天我們主要講解的都是最短路的相關算法,有的可以用于邊權為負數的情況,有的不可以,大家對這些算法如果有困難,一方面理解不容易另一方面代碼太長,大家可以慢慢消化,我們今天就講解到這里,我們下次博客再見!

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

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

相關文章

linux中如何在日志里面檢索nowStage不等于1的數據的指令

你想在 Linux 中查找日志文件中 nowStage 不等于 1 的所有 JSON 行&#xff0c;當前你已經使用了&#xff1a; Bash 深色版本 grep -rn "nowStage" ./ 這個命令可以找到包含 "nowStage" 字樣的所有行及其所在的文件名和行號&#xff0c;但還不能篩選出 no…

【習題】DevEco Studio的使用

判斷題 1. 如果代碼中涉及到一些網絡、數據庫、傳感器等功能的開發&#xff0c;均可使用預覽器進行預覽。 正確(True) 錯誤(False) 正確答案: 錯誤(False) 知識點 預覽器的使用。解析&#xff1a;預覽器只支持對頁面的預覽&#xff0c;如果代碼中涉及到一些網絡、數據庫、…

SpringBoot實現簡易直播

當下直播技術已經成為各類應用不可或缺的一部分&#xff0c;從社交媒體到在線教育&#xff0c;再到電子商務和游戲領域&#xff0c;直播功能正在被廣泛應用。 本文將介紹如何使用SpringBoot框架構建一個直播流推拉系統。 一、直播技術基礎 1.1 推流與拉流概念 直播系統的核心…

xcode 各版本真機調試包下載

下載地址 https://github.com/filsv/iOSDeviceSupport 使用方法&#xff1a; 添加到下面路徑中&#xff0c;然后退出重啟xcode /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport

DL00871-基于深度學習YOLOv11的盲人障礙物目標檢測含完整數據集

基于深度學習YOLOv11的盲人障礙物目標檢測&#xff1a;開啟盲人出行新紀元 在全球范圍內&#xff0c;盲人及視覺障礙者的出行問題一直是社會關注的重點。盡管技術不斷進步&#xff0c;許多城市的無障礙設施依然未能滿足盲人出行的實際需求。尤其是在復雜的城市環境中&#xff…

Python 訓練 day46

知識點回顧&#xff1a; 不同CNN層的特征圖&#xff1a;不同通道的特征圖什么是注意力&#xff1a;注意力家族&#xff0c;類似于動物園&#xff0c;都是不同的模塊&#xff0c;好不好試了才知道。通道注意力&#xff1a;模型的定義和插入的位置通道注意力后的特征圖和熱力圖 作…

TSN交換機正在重構工業網絡,PROFINET和EtherCAT會被取代嗎?

在工業自動化持續演進的今天&#xff0c;通信網絡的角色正變得愈發關鍵。 2025年6月6日&#xff0c;為期三天的華南國際工業博覽會在深圳國際會展中心&#xff08;寶安&#xff09;圓滿落幕。作為國內工業通信領域的技術型企業&#xff0c;光路科技&#xff08;Fiberroad&…

Qwen系列之Qwen3解讀:最強開源模型的細節拆解

文章目錄 1.1分鐘快覽2.模型架構2.1.Dense模型2.2.MoE模型 3.預訓練階段3.1.數據3.2.訓練3.3.評估 4.后訓練階段S1: 長鏈思維冷啟動S2: 推理強化學習S3: 思考模式融合S4: 通用強化學習 5.全家桶中的小模型訓練評估評估數據集評估細節評估效果弱智評估和民間Arena 分析展望 如果…

yolo模型精度提升策略

總結與行動建議 立即行動&#xff1a; 顯著增加6種相似BGA的高質量、多樣化訓練數據&#xff08;2倍以上是合理起點&#xff09;。 實施針對性數據增強&#xff1a; 設計模擬BGA實際成像挑戰&#xff08;反光、模糊、視角變化&#xff09;的增強方案。 升級模型與損失函數&am…

Kafka主題運維全指南:從基礎配置到故障處理

#作者&#xff1a;張桐瑞 文章目錄 主題日常管理1. 修改主題分區。2. 修改主題級別參數。3. 變更副本數。4. 修改主題限速。5.主題分區遷移。6. 常見主題錯誤處理常見錯誤1&#xff1a;主題刪除失敗。常見錯誤2&#xff1a;__consumer_offsets占用太多的磁盤。 主題日常管理 …

使用Docker部署MySQLRedis容器與常見命令

目錄 1. 檢查WSL配置2. 設置WSL版本3. 拉取MySQL鏡像4. 驗證鏡像5. 運行MySQL容器在WSL環境中使用以下命令啟動MySQL容器查看容器/鏡像的完整信息顯式指定宿主機掛載路徑可選&#xff1a;在Windows的cmd中使用以下命令啟動MySQL容器 6. 管理容器啟動已創建的容器查看運行中的容…

01__C++入門

一、C的語法框架 首先學習一門語言&#xff0c;我們需要了解語言的基本框架&#xff0c;這一小節&#xff0c;我們學習C的歷史應用&#xff0c;c和c的區別和c的標準 二、認識C 1、C的歷史 所有的主流C編譯器都支持這個版本的C&#xff08;1998年的版本&#xff09;。 2、C的應…

2024 CKA題庫+詳盡解析| 15、備份還原Etcd

目錄 免費獲取題庫配套 CKA_v1.31_模擬系統 15、 備份還原Etcd 題目&#xff1a; 開始操作: 1&#xff09;、切換集群 2&#xff09;、登錄master并提權 3&#xff09;、備份Etcd現有數據 4&#xff09;、驗證備份數據快照 5&#xff09;、查看節點和Pod狀態 6&am…

Flotherm許可的并發用戶數限制

在電子產品熱設計領域&#xff0c;Flotherm軟件以其卓越的性能和精確的仿真能力而受到廣大用戶的青睞。然而&#xff0c;在使用Flotherm軟件時&#xff0c;了解其許可的并發用戶數限制對于優化資源配置和提升工作效率至關重要。本文將詳細介紹Flotherm軟件許可的并發用戶數限制…

讀取寶塔方法,查找容別名存放位置

可以查到對應方法 根據參數名可知 查找到 得到位置

【1】跨越技術棧鴻溝:字節跳動開源TRAE AI編程IDE的實戰體驗

2024年初&#xff0c;人工智能編程工具領域發生了一次靜默的變革。當字節跳動宣布退出其TRAE項目&#xff08;一款融合大型語言模型能力的云端AI編程IDE&#xff09;時&#xff0c;技術社區曾短暫嘆息。然而這一退場并非終點——通過開源社區的接力&#xff0c;TRAE在WayToAGI等…

git連接本地倉庫以及gitee

參考:gitee創建新倉庫并上傳代碼_gitee新建倉庫導入代碼-CSDN博客 git初始化以及添加git分支 在idea查看master主分支 報錯 原因gitee推送更新失敗問題記錄&#xff1a;remote: error: hook declined to update refs/heads/master-CSDN博客 取消郵箱暴露

pocketflow庫實現guardrail

目錄 代碼代碼解釋1. 系統架構2. 核心組件詳解2.1 LLM調用函數2.2 UserInputNode&#xff08;用戶輸入節點&#xff09;2.3 GuardrailNode&#xff08;安全防護節點&#xff09;2.4 LLMNode&#xff08;LLM處理節點&#xff09; 3. 流程控制機制 示例運行 代碼 from pocketflo…

Fetch API 使用詳解:Bearer Token 與 localStorage 實踐

Fetch API&#xff1a;現代瀏覽器內置的用于發送 HTTP 請求的 API&#xff0c;Bearer Token&#xff1a;一種基于令牌的身份驗證方案&#xff0c;常用于 JWT 認證&#xff0c;localStorage&#xff1a;瀏覽器提供的持久化存儲方案&#xff0c;用于在客戶端存儲數據。 token是我…

Netty自定義協議解析

目錄 自定義協議設計 實現消息解碼器 實現消息編碼器 自定義消息對象 配置ChannelPipeline Netty提供了強大的編解碼器抽象基類,這些基類能夠幫助開發者快速實現自定義協議的解析。 自定義協議設計 在實現自定義協議解析之前,需要明確協議的具體格式。例如,一個簡單的…