算法訓練營day60 圖論⑩ Bellman_ford 隊列優化算法、判斷負權回路、單源有限最短路(修改后版本)

? ? ? ? 增加對最短路徑的優化算法、負權回路、單源有限最短的講解

Bellman_ford 隊列優化算法

--------------------------------------------------------------------------------

? ? ? ? 8.24更新:該算法是針對帶負值的最短路徑的優化算法,核心通過隊列來實現,代碼中visit數組來標記在隊列中的元素,以防重復入隊,每次循環一個節點的出度,即自該節點出發的邊,模擬過程中隊列判斷n次(均由隊列實現,具體次數無循環語句要求)

--------------------------------------------------------------------------------

????????我們之前的松弛算法,是對所有邊進行松弛,真正有效的松弛,只有松弛 邊(節點1->節點2) 和 邊(節點1->節點3)。而松弛 邊(節點4->節點6),邊(節點5->節點3)等等 都是無效的操作,因為 節點4 和 節點 5 都是沒有被計算過的節點。所以 Bellman_ford 算法 每次都是對所有邊進行松弛,其實是多做了一些無用功。

????????只需要對 上一次松弛的時候更新過的節點作為出發節點所連接的邊 進行松弛就夠了

????????基于以上思路,如何記錄 上次松弛的時候更新過的節點呢?用隊列來記錄。簡單理解就是每次mindist數組中被更新過的位置就是需要入棧的元素,然后棧頂元素進行松弛操作出棧,同時被修改的元素入棧,最后完成所有的循環(其實用棧也行,對元素順序沒有要求)

效率分析

????????如果圖越稠密,則 SPFA的效率越接近與 Bellman_ford。反之,圖越稀疏,SPFA的效率就越高。一般來說,SPFA 的時間復雜度為 O(K * N) K 為不定值,因為 節點需要計入幾次隊列取決于 圖的稠密度。

????????SPFA(隊列優化版Bellman_ford) 在理論上 時間復雜度更勝一籌,但實際上,也要看圖的稠密程度,如果 圖很大且非常稠密的情況下,雖然 SPFA的時間復雜度接近Bellman_ford,但實際時間消耗 可能是 SPFA耗時更多。

代碼實現

????????最根本的理解,我們這個代碼是以邊為主的,注意本題沒有 負權回路 。

import collectionsdef main():n, m = map(int, input().strip().split())edges = [[] for _ in range(n + 1)]for _ in range(m):src, dest, weight = map(int, input().strip().split())edges[src].append([dest, weight])minDist = [float("inf")] * (n + 1)minDist[1] = 0que = collections.deque([1])visited = [False] * (n + 1)visited[1] = Truewhile que:cur = que.popleft()visited[cur] = Falsefor dest, weight in edges[cur]:if minDist[cur] != float("inf") and minDist[cur] + weight < minDist[dest]:minDist[dest] = minDist[cur] + weightif visited[dest] == False:que.append(dest)visited[dest] = Trueif minDist[-1] == float("inf"):return "unconnected"return minDist[-1]if __name__ == "__main__":print(main())

Bellman_ford 判斷負權回路

--------------------------------------------------------------------------------

? ? ? ? 8.24更新:核心思路就是多松弛一次,看mindist數組有沒有變化(負權回路會導致mindist數組變化),優化算法中的判斷負權回路:如果節點加入隊列的次數 超過了 n-1次 ,那么該圖就一定有負權回路。

? ? ? ? 怎么判斷數組有沒有變化?還是一樣的邏輯,看有沒有變小即可

? ? ? ? 最后一點,普通方法把邊都遍歷一遍這種,沒有什么特別的說法,直接多松弛一次即可,但是優化算法中的負權回路,因為引入了隊列,所以一定記得對于隊列內已經進入的元素不要重復進入,(這個是上一題目中的基本內容了),這里的拓展我認為有一些主動寫錯來糾偏的部分了,反而可能更加容易引起誤導

--------------------------------------------------------------------------------

????????本題是要我們判斷 負權回路,也就是圖中出現環且環上的邊總權值為負數。如果在這樣的圖中求最短路的話, 就會在這個環里無限循環 (也是負數+負數 只會越來越小),無法求出最短路徑。

????????在上期博客中,bellman_ford 算法的核心就是一句話:對 所有邊 進行 n-1 次松弛。?在沒有負權回路的圖中,松弛 n 次以上 ,結果不會有變化。但本題有 負權回路,如果松弛 n 次,結果就會有變化了,因為 有負權回路 就是可以無限最短路徑(一直繞圈,就可以一直得到無限小的最短距離)。

????????那么解決本題的 核心思路,就是在?n-1 次松弛?的基礎上,再多松弛一次,看minDist數組 是否發生變化。

Bellman-Ford方法

import sysdef main():input = sys.stdin.readdata = input().split()index = 0n = int(data[index])index += 1m = int(data[index])index += 1grid = []for i in range(m):p1 = int(data[index])index += 1p2 = int(data[index])index += 1val = int(data[index])index += 1# p1 指向 p2,權值為 valgrid.append([p1, p2, val])start = 1  # 起點end = n    # 終點minDist = [float('inf')] * (n + 1)minDist[start] = 0flag = Falsefor i in range(1, n + 1):  # 這里我們松弛n次,最后一次判斷負權回路for side in grid:from_node = side[0]to = side[1]price = side[2]if i < n:if minDist[from_node] != float('inf') and minDist[to] > minDist[from_node] + price:minDist[to] = minDist[from_node] + priceelse:  # 多加一次松弛判斷負權回路if minDist[from_node] != float('inf') and minDist[to] > minDist[from_node] + price:flag = Trueif flag:print("circle")elif minDist[end] == float('inf'):print("unconnected")else:print(minDist[end])if __name__ == "__main__":main()

SPFA方法

? ? ? ? 這里涉及的問題是節點重復入隊,導致本應n-1次結束的過程,沒有按時結束,我們需要記錄哪些節點已經出隊列了,哪些節點在隊列里面,對于還在隊列內部的節點不要重復入隊

from collections import deque
from math import infdef main():n, m = [int(i) for i in input().split()]graph = [[] for _ in range(n+1)]min_dist = [inf for _ in range(n+1)]count = [0 for _ in range(n+1)]  # 記錄節點加入隊列的次數for _ in range(m):s, t, v = [int(i) for i in input().split()]graph[s].append([t, v])min_dist[1] = 0  # 初始化count[1] = 1d = deque([1])flag = Falsewhile d:  # 主循環cur_node = d.popleft()for next_node, val in graph[cur_node]:if min_dist[next_node] > min_dist[cur_node] + val:min_dist[next_node] = min_dist[cur_node] + valcount[next_node] += 1if next_node not in d: # 二刷的時候再好好理解d.append(next_node)if count[next_node] == n:  # 如果某個點松弛了n次,說明有負回路flag = Trueif flag:breakif flag:print("circle")else:if min_dist[-1] == inf:print("unconnected")else:print(min_dist[-1])if __name__ == "__main__":main()

Bellman_ford 單源有限最短路

--------------------------------------------------------------------------------

? ? ? ? 8.24更新:節點數量為n,起點到終點,最多是 n-1 條邊相連。 那么對所有邊松弛 n-1 次 就一定能得到 起點到達 終點的最短距離。這個n - 1要理解,這也是松弛的最基本邏輯,就不多講了。(如果對以上講解看不懂,建議詳看?kama94.城市間貨物運輸I?)

? ? ? ? 但是僅有這個理解是不夠的,這里我還是要吐槽一下,可能是我沒看視頻,我認為這道題目的文字版解析說的不好,可能是我沒有理解到位,我認為出現問題的本質是:在修改過程中修改了已經遍歷過的節點的值,地基變了,自然下一輪中所有的值都會修改,引起這個問題的本質是:路徑中存在負權回路,而不是文字版講解中說的:基于了本次松弛的 minDist數值,而不是上一次 松弛時候minDist的數值。這個講解歪曲了這個問題的本質,反而讓全文顯得很啰嗦并且具有誤導性。

? ? ? ? 解決這個問題的方法是:解決負權環路的判斷,如何解決?環路最少有兩條邊,隔開這兩條邊,也就是文字版解析中給出的解決方法,但是這個是后驗的,不可以在開始就把問題歸結到這一點上

? ? ? ? 最后dijkstra顯然是不能用的

--------------------------------------------------------------------------------

????????注意題目中描述是?最多經過 k 個城市的條件下,而不是一定經過k個城市,也可以經過的城市數量比k小,但要最短的路徑。對于部分路徑節點多但是距離短的結果增加了要求

????????在?這個系列的第一個題目 中我們講了:對所有邊松弛一次,相當于計算 起點到達 與起點一條邊相連的節點 的最短距離。節點數量為n,起點到終點,最多是 n-1 條邊相連。 那么對所有邊松弛 n-1 次 就一定能得到 起點到達 終點的最短距離。本題是最多經過 k 個城市, 那么是 k + 1條邊相連的節點。?

Bellman-Ford方法求解單源有限最短路

def main():# 輸入n, m = map(int, input().split())edges = list()for _ in range(m):edges.append(list(map(int, input().split() )))start, end, k = map(int, input().split())min_dist = [float('inf') for _ in range(n + 1)]min_dist[start] = 0# 只能經過k個城市,所以從起始點到中間有(k + 1)個邊連接# 需要鬆弛(k + 1)次for _ in range(k + 1):update = Falsemin_dist_copy = min_dist.copy()for src, desc, w in edges:if (min_dist_copy[src] != float('inf') and min_dist_copy[src] + w < min_dist[desc]):min_dist[desc] = min_dist_copy[src] + wupdate = Trueif not update:break# 輸出if min_dist[end] == float('inf'):print('unreachable')else:print(min_dist[end])if __name__ == "__main__":main()

SPFA方法求解單源有限最短路

from collections import deque
from math import infdef main():n, m = [int(i) for i in input().split()]graph = [[] for _ in range(n+1)]for _ in range(m):v1, v2, val = [int(i) for i in input().split()]graph[v1].append([v2, val])src, dst, k = [int(i) for i in input().split()]min_dist = [inf for _ in range(n+1)]min_dist[src] = 0  # 初始化起點的距離que = deque([src])while k != -1 and que:visited = [False for _ in range(n+1)]  # 用于保證每次松弛時一個節點最多加入隊列一次que_size = len(que)temp_dist = min_dist.copy()  # 用于記錄上一次遍歷的結果for _ in range(que_size):cur_node = que.popleft()for next_node, val in graph[cur_node]:if min_dist[next_node] > temp_dist[cur_node] + val:min_dist[next_node] = temp_dist[cur_node] + valif not visited[next_node]:que.append(next_node)visited[next_node] = Truek -= 1if min_dist[dst] == inf:print("unreachable")else:print(min_dist[dst])if __name__ == "__main__":main()

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

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

相關文章

Python 學習(十六) 下一代 Python 包管理工具:UV

目錄1. UV 介紹1.1 什么是UV&#xff1f;1.2 UV的核心優勢1.3 UV和其他工具對比1&#xff09;UV vs. pipvirtualenv2&#xff09;UV vs. Conda3&#xff09;UV vs. Poetry4&#xff09;功能對比表2. UV的安裝與常用命令2.1 安裝UV1&#xff09;使用官方安裝腳本&#xff08;推薦…

Redis學習筆記 ----- 緩存

一、什么是緩存 緩存&#xff08;Cache&#xff09;是數據交換的緩沖區&#xff0c;是存儲數據的臨時地方&#xff0c;一般讀寫性能較高。 &#xff08;一&#xff09;緩存的作用 降低后端負載&#xff1a;減少對數據庫等后端存儲的直接訪問壓力。提高讀寫效率&#xff0c;降低…

React響應式鏈路

文章目錄響應式鏈路的核心環節1.狀態定義與初始化2.狀態更新觸發&#xff08;狀態變更&#xff09;3.調度更新&#xff08;Scheduler&#xff09;4.重新渲染&#xff08;Render 階段&#xff09;5.協調&#xff08;Reconciliation&#xff09;與 Fiber 架構6.提交更新&#xff…

軟件設計師——計算機網絡學習筆記

一、計算機網絡 網絡基礎 1. 計算機網絡的分類2. 網絡拓撲結構 總線型(利用率低、干擾大、價格低) 星型(交換機形成的局域網、中央單元負荷大) 環型(流動方向固定、效率低擴充難) 樹型(總線型的擴充、分級結構) 分布式(任意節點連接、管理難成本高)一般來說&#xff0c;辦公室局…

1200 SCL學習筆記

一. IF. 如果。下面是一個起保停IF #I_start AND NOT #I_stop THEN //如果I_start接通 和 I_stop沒有接通#Q_run : 1; //輸出Q_run 接通 ELSIF #I_stop THEN //如果I_stop接通#Q_run : 0; //。。。。。。 END_IF;二. CASECASE…

單例模式與線程池

1. 單例模式單例模式是一種常用的設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來獲取這個實例。這種模式在需要控制資源訪問、管理共享狀態或協調系統行為時非常有用。單例模式的核心特點&#xff1a;私有構造函數&#xff1a;防止外部通過n…

Chrome和Edge如何開啟暗黑模式

Edge和Chrome瀏覽器都提供了實驗性功能&#xff0c;可以通過修改實驗性設置來開啟暗黑模式。 在瀏覽器地址欄中輸入edge://flags/&#xff08;Edge&#xff09;或chrome://flags/&#xff08;Chrome&#xff09;。在搜索框中輸入“dark”&#xff0c;找到與暗黑模式相關的選項。…

【科研繪圖系列】浮游植物的溶解性有機碳與初級生產力的關系

禁止商業或二改轉載,僅供自學使用,侵權必究,如需截取部分內容請后臺聯系作者! 文章目錄 介紹 數據準備 數據處理 溶解性有機碳(DOC)與初級生產力(NPP)的關系 溶解性有機碳(DOC)與光照強度(PAR)的關系 數據可視化 加載R包 數據下載 導入數據 畫圖1 畫圖2 總結 系統信…

IDEA相關的設置和技巧

IDEA相關的設置和技巧 我的博客對應文章地址 1.布局設置 IDEA的布局自定義程度很高&#xff0c;頂部工具欄&#xff0c;側邊欄都可以隨意定制&#xff0c;設置好的布局方案可以保存&#xff0c;在新項目中快速使用 1.1 工具欄設置 [!tip] 舉個例子&#xff1a;比如我要在頂部…

AWS Lambda 完全指南:解鎖無服務器架構的強大力量

在云計算的發展浪潮中,無服務器(Serverless) 架構已然成為構建現代應用的新范式。而在這場變革的中心,AWS Lambda 作為開創性的 Function-as-a-Service (FaaS) 服務,徹底改變了我們部署和運行代碼的方式。 本文將帶您深入探索 AWS Lambda,從核心概念、工作原理到高級實踐…

人工智能時代下普遍基本收入(UBI)試驗的實踐與探索——以美國硅谷試點為例

一、硅谷UBI試驗的最新進展&#xff08;2025年&#xff09;1. 試驗規模與資金來源圣克拉拉縣試點&#xff1a;硅谷所在地圣克拉拉縣針對脫離寄養家庭的年輕人開展UBI試驗&#xff0c;每月發放1000美元補貼&#xff0c;持續1-2年&#xff0c;覆蓋約60名參與者&#xff0c;成本約…

云計算之云主機Linux是什么?有何配置?如何選?

一、云環境如何選擇Linux發行版 1.1、Linux在各個領域的發展 Linux在各個領域的發展序號Linux發展領域說明1Linux在服務器領域的發展目前Linux在服務器領域已經占據95%的市場份額&#xff0c;同時Linux在服務器市場的迅速崛起&#xff0c;已經引起全球IT產業的高度關注&#xf…

XCVU13P-2FHGB2104E Xilinx(AMD)Virtex UltraScale+ FPGA

XCVU13P-2FHGB2104E 是 Xilinx&#xff08;AMD&#xff09;Virtex UltraScale FPGA 系列中的一款高性能芯片&#xff0c;適用于需要大量邏輯資源、高帶寬和高速數據傳輸的應用場景。作為該系列中的旗艦產品&#xff0c;XCVU13P-2FHGB2104I 結合了強大的處理能力和靈活的可編程性…

自動化單詞例句獲取系統設計方案

方案一 (網絡爬蟲) 這個方案的核心思路是:創建一個自動化的腳本,該腳本會讀取你 MongoDB 中的單詞,然后去一個免費的在線詞典網站上抓取這些單詞的例句,最后將抓取到的例句存回你的 MongoDB 數據庫中對應的單詞條目下。 一、 核心思路與技術選型 自動化腳本: 我們將使用 P…

WPF Alert彈框控件 - 完全使用指南

WPF Alert彈框控件 - 完全使用指南概述快速開始nuget安裝與引用基本用法功能特性詳細說明AlertType 枚舉方法參數詳解Show 方法&#xff08;局部彈窗&#xff09;ShowGlobal 方法&#xff08;全局彈窗&#xff09;完整示例代碼XAML 布局C# 代碼實現界面演示功能特性對比表格自定…

可視化-模塊1-HTML-01

1-軟件下載&#xff1a; 軟件名稱&#xff1a;HBuilderX 官網地址&#xff1a; https://www.dcloud.io/hbuilderx.html 下載文佳-解壓縮-打開exe文件 創建快捷方式至桌面 2-創建項目 【普通項目】-【基本HTML項目】-【項目名&#xff1a;week1-1】 【index】輸入&#xff1…

機器翻譯 (Machine Translation) 經典面試筆試50題(包括詳細答案)

更多內容請見: 機器翻譯修煉-專欄介紹和目錄 文章目錄 第一部分:基礎理論與概念 (1-15題) 1. 題目: 什么是機器翻譯(MT)?請簡述其發展歷程中的幾個主要范式。 2. 題目: 機器翻譯的主要評價指標有哪些?請詳細解釋BLEU指標的計算原理和優缺點。 3. 題目: 什么是平行語料…

linux中文本文件操作之grep命令

文章目錄背景案例demo環境方式一、安裝wsl方式二、安裝grep一、查找指定字符串二、忽略大小寫查找三、查找時顯示行號四、統計匹配的次數五、精準匹配一個單詞六、顯示匹配上下文七、只顯示匹配的內容八、按固定字符串匹配背景 在日常運維中會對日志文件&#xff0c;使用grep命…

鏈表漫游指南:C++ 指針操作的藝術與實踐

文章目錄0. 前言1. 鏈表的分類2. 單鏈表的實現2.1 鏈表的基本結構——節點&#xff08;Node&#xff09;2.2 核心操作詳解2.2.1 構造和析構2.2.2 插入操作2.2.3 刪除操作2.3.4 其他操作2.4 總結3. 雙向鏈表的實現3.1 基本結構設計3.2 基本操作3.2.1 初始化與銷毀3.2.2 插入與刪…

Claude Code賦能企業級開發:外賣平臺核心系統的智能化重構

開篇&#xff1a;萬億市場背后的技術挑戰中國外賣市場日訂單量超過1億單&#xff0c;每一單背后都是一個復雜的技術鏈條&#xff1a;用戶下單→商家接單→騎手搶單→實時配送→評價反饋。構建這樣一個支撐千萬級并發、涉及地理位置計算、實時調度、支付結算的超級平臺&#xff…