【數據結構與算法】圖 Floyd算法

相關題目:?

1334. 閾值距離內鄰居最少的城市 - 力扣(LeetCode)

資料 :?

Floyd算法原理及公式推導 - 知乎

Floyd 算法是一種經典的動態規劃算法,用與求解圖中所有頂點之間的最短短路路徑。它由Robert Floyd? 于1962 年提出,核心思想是通過“中間頂點”逐步松弛路徑長度,最終得到任意兩點間的最短距離。

算法核心 :?

圖的類型:無向圖 ,有向圖(注意邊的方向性)

邊權特性: 支持負權邊,但是不允許“包含負權邊的回路”,否則會導致路徑長度無線減小,無法收斂。

圖的存儲:??

使用鄰接矩陣存儲,用于快速訪問任意兩點間的邊權。

算法原理步驟

動態規劃 狀態定義??

定義 dp[k][i][j]=表示只允許使用前k個節點作為中間節點 ,頂點 i 到頂點j 的最短距離。

根據狀態轉移:?

不選擇第k個節點 作為中間節點:

dp[k][i][j]=dp[k-1][i][j]

選擇第k個頂點組委中間節點:路徑拆分為i->k->j

dp[k][i][j] =dp[k-1][i][j]+dp[k-1][i][j].

狀態轉移方程為:

dp[k][i][j]=min(dp[k-1][i][j],dp[k-1][i][k]+dp[k-1][k][j])

空間優化(關鍵)

觀察dp[k][...]? ?僅依賴dp[k-1][...]? ,因此無需存儲所有k 層狀態,可以直接用二維數組dist覆蓋更新

(k 作為外層循環,每次更新dist[i]j[ 時復用之前的結果])。

實現步驟

假設? 圖中有n個頂點,鄰接矩陣初始化為dist ,步驟如下:?

初始化鄰接矩陣

對頂點i, dist[i][i]=0? 自身到自身的距離為0?

如果頂點i和j 直接有直接的邊,權重為w 則dist[i][j]=w

如果頂點i 和j 無直接邊,dist[i][j]=\infty?, 表示不可達,通常用一個極大值如10^9

外層循環(枚舉中間節點k)

遍歷所有可能的中間頂點k(從1到n)

中間循環: 枚舉起點i:

?遍歷所有可能的起點i (從1到n)

內側循環:枚舉終點 j

遍歷所有可能的終點j , (1到 n ),執行松弛操作,

dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

(可選)檢測負權回路

算法結束后,若存在?(dist[i][i] < 0),則說明圖中存在包含頂點?i?的負權回路(因為自身到自身的距離不可能為負)

代碼?

c++

#include <iostream>
#include <vector>
#include <climits>
using namespace std;const int INF = INT_MAX / 2;  // 避免加法溢出int main() {int n, m;  // n: 頂點數, m: 邊數cin >> n >> m;// 1. 初始化鄰接矩陣vector<vector<int>> dist(n + 1, vector<int>(n + 1, INF));for (int i = 1; i <= n; ++i) {dist[i][i] = 0;  // 自身到自身距離為0}// 讀入邊:u -> v,權值 wfor (int i = 0; i < m; ++i) {int u, v, w;cin >> u >> v >> w;dist[u][v] = w;  // 若為無向圖,需額外添加 dist[v][u] = w}// 2. Floyd 算法核心(k: 中間頂點,i: 起點,j: 終點)for (int k = 1; k <= n; ++k) {for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {// 若 i->k 或 k->j 不可達,則跳過(避免 INF + INF 溢出)if (dist[i][k] != INF && dist[k][j] != INF) {dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);}}}}// 3. 輸出所有頂點間的最短距離cout << "所有頂點間的最短距離:" << endl;for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {if (dist[i][j] == INF) {cout << "INF ";  // 不可達} else {cout << dist[i][j] << " ";}}cout << endl;}// 4. 檢測負權回路bool has_negative_cycle = false;for (int i = 1; i <= n; ++i) {if (dist[i][i] < 0) {has_negative_cycle = true;break;}}if (has_negative_cycle) {cout << "圖中存在負權回路!" << endl;}return 0;
}

python?

import sys
# 避免類似 C++ 中 INT_MAX 溢出問題,使用一個足夠大的數表示“不可達”
INF = float('inf')def main():# 讀取輸入(頂點數 n,邊數 m)# 注:Python 中 input() 讀取單行,需拆分字符串獲取整數;若輸入較大可改用 sys.stdin 提速n, m = map(int, sys.stdin.readline().split())# 1. 初始化鄰接矩陣:dist[i][j] 表示頂點 i 到 j 的初始距離# 頂點編號從 1 開始(與 C++ 保持一致,避免索引偏移)dist = [[INF] * (n + 1) for _ in range(n + 1)]# 自身到自身的距離為 0for i in range(1, n + 1):dist[i][i] = 0# 讀入 m 條邊:u -> v,權值 w(有向邊)for _ in range(m):u, v, w = map(int, sys.stdin.readline().split())# 若存在多條從 u 到 v 的邊,保留權值最小的一條(與原 C++ 邏輯一致)dist[u][v] = w# 【若為無向圖】需添加以下一行(無向邊等價于雙向有向邊):# dist[v][u] = w# 2. Floyd 算法核心:三層循環枚舉中間頂點、起點、終點# k:中間頂點(允許經過前 k 個頂點時更新最短路徑)for k in range(1, n + 1):# i:路徑起點for i in range(1, n + 1):# j:路徑終點for j in range(1, n + 1):# 跳過不可達的情況(避免 INF + INF 無意義計算)if dist[i][k] != INF and dist[k][j] != INF:# 松弛操作:更新 i->j 的最短距離if dist[i][j] > dist[i][k] + dist[k][j]:dist[i][j] = dist[i][k] + dist[k][j]# 3. 輸出所有頂點間的最短距離(格式與 C++ 一致)print("所有頂點間的最短距離:")for i in range(1, n + 1):row = []for j in range(1, n + 1):if dist[i][j] == INF:row.append("INF")else:row.append(str(dist[i][j]))# 用空格連接一行的元素,與 C++ 輸出格式對齊print(' '.join(row))# 4. 檢測負權回路:若存在頂點 i 滿足 dist[i][i] < 0,說明有負權回路has_negative_cycle = Falsefor i in range(1, n + 1):if dist[i][i] < 0:has_negative_cycle = Truebreakif has_negative_cycle:print("圖中存在負權回路!")if __name__ == "__main__":main()

不可達值(INF): Python 中用 float('inf') 表示 “無窮大”,比 C++ 的 INT_MAX/2 更直觀,且天然避免整數溢出問題(無需擔心 INF + INF 超出范圍)。

鄰接矩陣初始化: 用 Python 列表推導式 [[INF]*(n+1) for _ in range(n+1)] 創建 (n+1)×(n+1) 的矩陣(頂點編號從 1 開始,與 C++ 一致,減少邏輯偏移)。

輸入處理: 使用 sys.stdin.readline() 替代 input(),處理大量輸入時效率更高(適配題目中可能的大規模圖數據);通過 map(int, ...split()) 拆分輸入字符串為整數,與 C++ 的 cin >> 邏輯一致。 核心松弛操作: 保留三層循環的順序(k→i→j),僅將 C++ 的 min() 函數替換為 Python 的條件判斷(if dist[i][j] > ...),邏輯完全等價,且更符合 Python 代碼習慣。

輸出格式: 用列表 row 收集每行的輸出內容,最后通過 ' '.join(row) 用空格連接,確保輸出格式與 C++ 一致(如 “INF” 對應不可達,數字對應最短距離)。 負權回路檢測: 保留原邏輯 —— 遍歷所有頂點 i,若 dist[i][i] < 0,說明存在經過 i 的負權回路(因為 “自身到自身的最短路徑” 不可能為負)。

示例?

示例1

輸入(3 個頂點,4 條有向邊):

plaintext

3 4
1 2 2
1 3 6
2 3 1
3 1 -4

輸出:

所有頂點間的最短距離: 0 2 3 -3 0 1 -4 -2 0 圖中存在負權回路!

該示例中,dist[1][1] = 0、dist[2][2] = 0、dist[3][3] = 0 看似無負,但實際計算過程中會發現循環 1→2→3→1 的總權值為 2+1+(-4) = -1 < 0,最終代碼會正確檢測出負權回路。

示例2

無負權邊的有向圖示例

中間頂點如何優化最短路徑

示例場景:4 個頂點的有向圖

假設我們有一個包含 4 個頂點(編號 1~4)的有向圖,邊的連接和權值如下(邊的方向和權重是核心):

  • 1 → 2,權值 3
  • 1 → 3,權值 6
  • 2 → 3,權值 2
  • 2 → 4,權值 5
  • 3 → 4,權值 1
  • 4 沒有出邊

第一步:明確輸入格式

根據代碼的輸入要求(先輸入頂點數?n?和邊數?m,再輸入?m?條邊的起點、終點、權值),該示例的輸入如下:

plaintext

4 5
1 2 3
1 3 6
2 3 2
2 4 5
3 4 1

第二步:算法執行邏輯拆解(核心步驟)

我們會按 Floyd 算法的三層循環(中間頂點?k?→ 起點?i?→ 終點?j),逐步展示鄰接矩陣?dist?的更新過程,理解 “中間頂點如何縮短路徑”。

1. 初始化鄰接矩陣

初始時,dist[i][j]?的規則:

  • 自身到自身:dist[i][i] = 0
  • 有直接邊:dist[i][j] = 邊權
  • 無直接邊:dist[i][j] = INF(用??表示)

初始?dist?矩陣(行是起點,列是終點):

起點 \ 終點1234
1036
2025
301
40

2. 枚舉中間頂點 k=1(允許經過頂點 1 優化路徑)

此時檢查所有 i→j,看是否能通過 i→1→j 縮短路徑。 由于頂點 1 的出邊只有 1→2、1→3,且大部分 i→1 不可達(如 i=2,3,4 到 1 是 ∞),因此矩陣無更新。

3. 枚舉中間頂點?k=2(允許經過頂點 2 優化路徑)

檢查所有?i→j,看是否能通過?i→2→j?縮短路徑,關鍵更新如下:

  • 對于?i=1, j=3:原路徑 1→3 權值 6;新路徑 1→2→3 權值?3+2=5?→ 更新?dist[1][3] = 5
  • 對于?i=1, j=4:原路徑 1→4 是?;新路徑 1→2→4 權值?3+5=8?→ 更新?dist[1][4] = 8

更新后的?dist?矩陣:

起點 \ 終點1234
10358
2025
301
40
4. 枚舉中間頂點?k=3(允許經過頂點 3 優化路徑)

檢查所有?i→j,看是否能通過?i→3→j?縮短路徑,關鍵更新如下:

  • 對于?i=1, j=4:原路徑 1→4 權值 8;新路徑 1→3→4 權值?5+1=6?→ 更新?dist[1][4] = 6
  • 對于?i=2, j=4:原路徑 2→4 權值 5;新路徑 2→3→4 權值?2+1=3?→ 更新?dist[2][4] = 3

更新后的?dist?矩陣:

起點 \ 終點1234
10356
2023
301
40
5. 枚舉中間頂點?k=4(允許經過頂點 4 優化路徑)

由于頂點 4 沒有出邊(所有?4→j?除了自身都是?),因此矩陣無更新

第三步:代碼輸出結果

將上述輸入代入 Python 代碼,最終輸出如下(包含所有頂點間的最短距離,且無負權回路):

plaintext

所有頂點間的最短距離:
0 3 5 6
INF 0 2 3
INF INF 0 1
INF INF INF 0

結果解讀

輸出矩陣的每一行代表 “從當前起點到所有終點的最短距離”:

  • 起點 1 到各終點:1→1(0)、1→2(3)、1→3(5,1→2→3)、1→4(6,1→2→3→4)
  • 起點 2 到各終點:2→1(不可達)、2→2(0)、2→3(2)、2→4(3,2→3→4)
  • 起點 3 到各終點:3→1/2(不可達)、3→3(0)、3→4(1)
  • 起點 4 到各終點:4→1/2/3(不可達)、4→4(0)

這與我們手動拆解的 “最優路徑” 完全一致,驗證了代碼的正確性。

額外測試:含負權邊(無負權回路) 若在上述示例中添加一條邊 3→1,權值 -2(無負權回路),輸入變為: plaintext 4 6 1 2 3 1 3 6 2 3 2 2 4 5 3 4 1 3 1 -2 代碼會檢測到 “無負權回路”,且更新后的 dist[2][1] 會變為 2→3→1 的權值 2 + (-2) = 0,dist[3][1] = -2 等,進一步體現 Floyd 算法對負權邊的支持。

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

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

相關文章

衛星通信天線的指向精度,含義、測量和計算

衛星通信天線的指向精度&#xff0c;含義、測量和計算我們在衛星通信天線的技術規格書中&#xff0c;都會看到天線指向精度這個指標。一般來說&#xff0c;技術規格書上的天線指向精度的參數是這么寫的&#xff1a;“天線指向精度≤1/10半功率波束帶寬”今天這個文章&#xff0…

基于LSTM與3秒級Tick數據的金融時間序列預測實現

數據加載模塊解析 def load_data(filepath):df pd.read_csv(filepath)return df該函數承擔基礎數據采集職責&#xff0c;通過Pandas庫讀取CSV格式的高頻交易數據&#xff08;典型如股票分筆成交明細&#xff09;。輸入參數為文件路徑字符串&#xff0c;輸出結構化DataFrame對象…

C# --- Field and Property

C# --- Field and Property字段 (Field) vs. 屬性 (Property)Property的聲明初始化方法單例類property錯誤初始化導致線程泄漏字段 (Field) vs. 屬性 (Property) 字段 (Field) - 數據的存儲容器 字段是直接在類或結構中聲明的變量。它是存儲數據的地方&#xff0c;是對象狀態的…

【Python】實現一個文件夾快照與比較工具

1. 工具簡介 在日常開發、項目管理或備份場景中&#xff0c;我們經常需要知道某個文件夾中的文件是否發生變化&#xff0c;例如&#xff1a; 項目源碼是否新增或修改文件&#xff1f;數據集是否被不小心刪除或篡改&#xff1f;備份文件夾是否和上次一致&#xff1f; 本教程將教…

LINUX913 shell:set ip [lindex $argv 0],\r,send_user,spawn ssh root@ip “cat “

問題 獲取公鑰 [codesamba ~]$ cat pub.sh #!/bin/usr/expect set ip "$1" set password 123456 set timeout 20 spawn ssh root192.168.235.100:cat ~/.ssh/id_rsa.pub expect { "yes/no" {send "yes/r";exp_continue} "password:" {…

Acwing算法基礎課--鏈表

一、單鏈表 AcWing 826. 單鏈表 代碼 N 100010 idx 0 e [0] * N ne [0] * N head -1def init():global idx,headidx 0head -1def add_head(x):global idx,heade[idx] xne[idx] headhead idxidx 1def delete(k):ne[k] ne[ne[k]]def add_k(k,x):global idxe[idx] …

AI表征了西方的有界,AI+體現了東方的無界

AI表征了西方的有界&#xff0c;AI體現了東方的無界&#xff0c;試圖通過文化差異的視角來對比傳統AI&#xff08;AI&#xff09;與增強型或融合型AI&#xff08;AI&#xff09;的特征。一、“AI表征了西方的有界”西方的“有界”可以理解為&#xff1a;1、邏輯清晰、結構嚴謹&…

LabVIEW泵輪檢測

?在現代制造業蓬勃發展的浪潮下&#xff0c;汽車行業也迎來了高速發展期。液力變矩器作為實現車輛自動變速的關鍵零件產品&#xff0c;在汽車動力系統中扮演著不可或缺的角色。泵輪作為液力變矩器的核心組成部分&#xff0c;其生產質量直接影響著液力變矩器的性能。因此&#…

RT-DETRv2 中的坐標回歸機制深度解析:為什么用 `sigmoid(inv_sigmoid(ref) + delta)` 而不是除以圖像尺寸?

引言&#xff1a;一個看似簡單的公式&#xff0c;背后藏著工業級設計智慧 在閱讀 RT-DETRv2&#xff08;Real-Time DETR v2&#xff09;源碼時&#xff0c;我曾被一行代碼深深震撼&#xff1a; inter_ref_bbox F.sigmoid(bbox_head[i](output) inverse_sigmoid(ref_points_de…

簡單了解一下GraphRAG

傳統RAG的缺點 當我們將一段文本信息以句子分割后&#xff0c;存入到向量數據庫中。用戶提問“老王喜歡吃什么”&#xff0c;這個問題會與向量數據庫中的許多句子關聯性比較強&#xff0c;能返回準確且具體的信息。 但是&#xff0c;若是問題換成“出現了幾次西瓜”&#xff0c…

HTTP 狀態碼背后的邏輯:從請求到響應的完整流程解析(含完整流程圖)

在日常的 Web 開發與 API 調試中&#xff0c;我們經常會遇到各種 HTTP 狀態碼 ——404 Not Found、401 Unauthorized、500 Internal Server Error... 這些數字背后并非隨機出現&#xff0c;而是服務器處理請求過程中不同階段的 "反饋信號"。理解這些狀態碼的觸發邏輯…

Vue:下拉框多選影響行高

目錄 一、 出現場景二、 解決方案 一、 出現場景 在使用el-select增加multiple屬性進行多選時&#xff0c;會出現高度塌陷的情況 二、 解決方案 首先需要在el-select中增加collapse-tags屬性&#xff0c;并在style中增加如下樣式 方案一 <style scoped> ::v-deep .e…

如何在高通躍龍QCS6490 Arm架構上使用Windows 11 IoT企業版?

1.簡介研華已將高通躍龍QCS6490 技術應用于嵌入式模塊、單板電腦和AI攝像頭等各種規格的嵌入式硬件中。QCS6490平臺支持全面的操作系統生態系統&#xff0c;包括Windows、Ubuntu、Yocto和 Android。Windows 11 IoT企業版是微軟新一代的物聯網操作系統&#xff0c;具有更強的安全…

阿里云國際代理:如何利用RDS構建高可用、可擴展的數據庫架構

講下云數據庫RDS案例解析&#xff0c;若在上云或用云過程中有不懂的&#xff0c;可尋云樞國際yunshuguoji助力免卡上云用云。1、RDS MySQL數據庫代理支持讀寫分離、連接保持、就近訪問、事務拆分、連接池、SSL加密等功能&#xff0c;能夠降低主實例負載&#xff0c;提高實例可用…

C++之特殊類設計

文章目錄前言一、 設計一個不能被拷貝的類1. C98 實現方式2. C11 實現方式二、設計一個只能在堆上創建對象的類1. 方法一&#xff1a;析構函數私有&#xff0c;提供destory接口釋放資源2. 方法二&#xff1a;構造函數私有三、 設計一個只能在棧上創建對象的類1. 實現方式四、設…

TupiTube,一款免費開源的 2D 動畫創作工具

TupiTube&#xff0c;一款免費開源的 2D 動畫創作工具 ** ** 功能 ** &#xff1a;開源、免費的 2D 動畫軟件&#xff0c;界面簡單&#xff0c;支持逐幀動畫、剪紙動畫、定格動畫&#xff0c;能導入素材并導出多種視頻和圖片格式&#xff0c;適合兒童、學生和動畫愛好者入門創作…

MoE架構訓練系統設計:專家并行與門控網絡優化策略

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;注冊即送-H卡級別算力&#xff0c;80G大顯存&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生更享專屬優惠。 摘要 混合專家&#xff08;Mixture of Experts&#xf…

使用Python爬蟲,selenium和requests誰更強?

py爬蟲的話&#xff0c;selenium和reqeusts誰更強&#xff0c;selenium是不是能完全取代requests? 答案基本是可以的&#xff0c;selenium適合動態網頁抓取&#xff0c;因為它可以控制瀏覽器去點擊、加載網頁&#xff0c;requests則比較適合靜態網頁采集&#xff0c;它非常輕…

編譯原理-文法壓縮練習

這個任務的目標就是把一個給定的文法變得“干凈”和“高效”&#xff0c;剔除所有無用的部分。根據幻燈片&#xff0c;無用的&#xff08;多余的&#xff09;規則分為兩大類&#xff1a; 不可達規則&#xff1a;規則的“頭”&#xff08;左部非終結符&#xff09;從起始符號出發…

GPU硬件架構和配置的理解

從公司架構理解GPU架構想象一個GPU就像一家大型科技公司&#xff0c;它的任務是處理圖形和計算任務&#xff08;“干活”&#xff09;。硬件概念公司架構比喻作用和特點Platform (平臺)集團公司最大的獨立實體。比如谷歌Alphabet是一個集團公司&#xff0c;它旗下有谷歌、Waymo…