Johnson

理論

全源最短路算法

  1. Floyd 算法,時間復雜度為 O(n3)
  2. 跑 n 次 Bellman - Ford 算法,時間復雜度是 O(n2m)
  3. 跑 n 次 Heap - Dijkstra 算法,時間復雜度是 O(nmlogm)
    第 3 種算法被 Johnson 做了改造,可以求解帶負權邊的全源最短路。

Johnson(約翰遜)算法
4. 新建一個虛擬源點 0,從該點向其他所有點連一條邊權為 0 的邊,再用spfa 算法求出從 0 號點到其他所有點的最短路 h(i)。
5. 將新圖的邊權改造為 w(u,v) + h(u) - h(v),這樣能確保邊權非負。
6. 以每個點為起點,跑 n 輪 Heap - Dijkstra 算法,求出任意兩點間最短路。
![在這里插入圖片描述](https://i-blog.csdnimg.cn/direct/900fec77653a4d379bc6fdad4e0f378a.pn

  1. 以下是結合Johnson算法對這幅圖的分析:
    1. 構建虛擬源點及初始操作
    圖中節點0是Johnson算法里新添加的虛擬源點 ,從它向節點1、2、3、4分別連了邊權為0的邊(綠色邊)。接下來要用SPFA算法求從0號虛擬源點到其他所有節點的最短路 h ( i ) h(i) h(i) 。比如從節點0到節點1的邊權為0 ,如果不存在更短路徑, h ( 1 ) h(1) h(1) 初始就是0 ;從節點0到節點4邊權為0 ,若沒有其他路徑干擾, h ( 4 ) h(4) h(4) 也為0 ;從節點0到節點2邊權為-5 ,0 ->3->2。圖中綠色數字即為初始操作(SPFA)后虛擬節點到個其余各個點的距離。
    2. 邊權改造
    根據Johnson算法,需要將圖中各邊的邊權改造為 w ( u , v ) + h ( u ) ? h ( v ) w(u, v)+h(u) - h(v) w(u,v)+h(u)?h(v) ,以此確保邊權非負。例如,對于節點1到節點2這條邊,原始邊權 w ( 1 , 2 ) w(1, 2) w(1,2) 為-1 , h ( 1 ) = 0 h(1)=0 h(1)=0 h ( 2 ) = ? ? 5 h(2)= - -5 h(2)=??5 ,則新邊權為 0 + ? 1 ? ( ? 5 ) = 4 0 + -1 - (-5)=4 0+?1?(?5)=4 。途中紅色數字為改造后的邊權,黑色數字為改造前的邊權。
    3. 計算全源最短路
    完成邊權改造后,以每個點為起點,運行n輪Heap - Dijkstra算法(n為圖中節點數,這里n = 4 ,不包含虛擬源點0 ),從而求出圖中任意兩點間的最短路。

各個最短路算法分析:

BFSHeap-DijkstraSPFAFloydJohnson
最短路類型最少步數單源單源全源全源
建圖鄰接矩陣鄰接表鄰接表鄰接矩陣鄰接表
算法貪心,松弛貪心,松弛插點法貪心,松弛
優化隊列優先隊列隊列優先隊列
負邊權不能
判負環不能
時間復雜度O(n + m)O(mlogm)O(nm)O(n3)O(nmlogm)
圖的大小大/中
n=10?, m=10?
大/中
n=10?, m=10?
中/小
n=103, m=10?

n=102
中/小
n=103, m=103

例題

https://www.luogu.com.cn/problem/P5905

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int INF = 1e9;
// 定義邊的結構體,包含目標節點 v 和邊的權重 w
struct edge { int v, w; };
// 鄰接表存儲圖,e[i] 存儲從節點 i 出發的所有邊
vector<edge> e[N];
// vis 數組用于標記節點是否在隊列中,cnt 數組用于記錄每個節點入隊的次數
int vis[N], cnt[N];
// h 數組用于存儲從虛擬源點到各節點的最短路,d 數組用于存儲從某個源點到各節點的最短路
long long h[N], d[N];
int n, m;// 使用 SPFA 算法計算從虛擬源點 0 到其他所有節點的最短路
void spfa() {// 定義一個隊列用于存儲待處理的節點queue<int> q;// 初始化 h 數組為一個很大的值,memset(63) 相當于將每個元素初始化為一個較大的數memset(h, 63, sizeof h);memset(vis, false, sizeof vis);// 虛擬源點到自身的距離為 0h[0] = 0;// 標記虛擬源點在隊列中vis[0] = 1;// 將虛擬源點加入隊列q.push(0);while (q.size()) {int u = q.front();q.pop();// 標記該節點不在隊列中vis[u] = 0;// 遍歷從節點 u 出發的所有邊for (auto ed : e[u]) {// 獲取目標節點 v 和邊的權重 wint v = ed.v, w = ed.w;// 如果通過節點 u 到達節點 v 的距離更短,則更新 h[v]if (h[v] > h[u] + w) {h[v] = h[u] + w;// 更新節點 v 的入隊次數cnt[v] = cnt[u] + 1;// 如果某個節點入隊次數超過 n 次,說明存在負環if (cnt[v] > n) {printf("-1\n");// 存在負環,程序退出exit(0);}// 如果節點 v 不在隊列中,則將其加入隊列if (!vis[v]) {q.push(v);vis[v] = 1;}}}}
}// 使用 Dijkstra 算法計算從源點 s 到其他所有節點的最短路
void dijkstra(int s) {// 定義一個優先隊列,用于存儲待處理的節點,按照距離從小到大排序priority_queue<pair<long long, int>> q;// 初始化 d 數組為無窮大for (int i = 1; i <= n; i++) {d[i] = INF;}// 初始化 vis 數組為 false,表示所有節點都未被處理memset(vis, false, sizeof vis);// 源點到自身的距離為 0d[s] = 0;// 將源點加入優先隊列q.push({ 0,s });// 當優先隊列不為空時進行處理while (q.size()) {// 取出隊首節點int u = q.top().second;q.pop();// 如果該節點已經被處理過,則跳過if (vis[u]) {continue;}// 標記該節點已被處理vis[u] = 1;// 遍歷從節點 u 出發的所有邊for (auto ed : e[u]) {// 獲取目標節點 v 和邊的權重 wint v = ed.v;int w = ed.w;// 如果通過節點 u 到達節點 v 的距離更短,則更新 d[v]if (d[v] > d[u] + w) {d[v] = d[u] + w;// 如果節點 v 未被處理,則將其加入優先隊列if (!vis[v]) {q.push({ -d[v],v });}}}}
}int main() {cin >> n >> m;// 輸入每條邊的信息,并將其加入鄰接表for (int i = 0; i < m; i++) {int a, b, c;cin >> a >> b >> c;e[a].push_back({ b,c });}// 從虛擬源點 0 向其他所有節點添加一條邊權為 0 的邊for (int i = 1; i <= n; i++) {e[0].push_back({ i,0 });//加虛擬邊}// 調用 SPFA 算法計算從虛擬源點到其他所有節點的最短路spfa();// 對圖的邊權進行重新計算,確保所有邊權非負for (int u = 1; u <= n; u++) {for (auto& ed : e[u]) {ed.w += h[u] - h[ed.v];//構造新邊}}// 以每個節點為源點,調用 Dijkstra 算法計算最短路for (int i = 1; i <= n; i++) {dijkstra(i);long long ans = 0;// 計算從源點 i 到其他所有節點的最短路的加權和for (int j = 1; j <= n; j++) {// 如果節點 j 不可達,則使用無窮大計算if (d[j] == INF) {ans += (long long)j * INF;}// 否則,使用實際距離計算else {ans += (long long)j * (d[j] + h[j] - h[i]);}}// 輸出結果printf("%lld\n", ans);}return 0;
}

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

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

相關文章

Exce格式化批處理工具詳解:高效處理,讓數據更干凈!

Exce格式化批處理工具詳解&#xff1a;高效處理&#xff0c;讓數據更干凈&#xff01; 1. 概述 在數據分析、報表整理、數據庫管理等工作中&#xff0c;數據清洗是不可或缺的一步。原始Excel數據常常存在格式不統一、空值、重復數據等問題&#xff0c;影響數據的準確性和可用…

(三十七)Dart 中使用 Pub 包管理系統與 HTTP 請求教程

Dart 中使用 Pub 包管理系統與 HTTP 請求教程 Pub 包管理系統簡介 Pub 是 Dart 和 Flutter 的包管理系統&#xff0c;用于管理項目的依賴。通過 Pub&#xff0c;開發者可以輕松地添加、更新和管理第三方庫。 使用 Pub 包管理系統 1. 找到需要的庫 訪問以下網址&#xff0c…

代碼隨想錄算法訓練營第三十五天 | 416.分割等和子集

416. 分割等和子集 題目鏈接&#xff1a;416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; 文章講解&#xff1a;代碼隨想錄 視頻講解&#xff1a;動態規劃之背包問題&#xff0c;這個包能裝滿嗎&#xff1f;| LeetCode&#xff1a;416.分割等和子集_嗶哩嗶哩_bilibi…

HTTP 教程 : 從 0 到 1 全面指南 教程【全文三萬字保姆級詳細講解】

目錄 HTTP 的請求-響應 HTTP 方法 HTTP 狀態碼 HTTP 版本 安全性 HTTP/HTTPS 簡介 HTTP HTTPS HTTP 工作原理 HTTPS 作用 HTTP 與 HTTPS 區別 HTTP 消息結構 客戶端請求消息 服務器響應消息 實例 HTTP 請求方法 各個版本定義的請求方法 HTTP/1.0 HTTP/1.1 …

spring功能匯總

1.創建一個dao接口&#xff0c;實現類&#xff1b;service接口&#xff0c;實現類并且service里用new創建對象方式調用dao的方法 2.使用spring分別獲取dao和service對象(IOC) 注意 2中的service里面獲取dao的對象方式不用new的(DI) 運行測試&#xff1a; 使用1的方式創建servic…

Vue.js 實現下載模板和導入模板、數據比對功能核心實現。

在前端開發中&#xff0c;數據比對是一個常見需求&#xff0c;尤其在資產管理等場景中。本文將基于 Vue.js 和 Element UI&#xff0c;通過一個簡化的代碼示例&#xff0c;展示如何實現“新建比對”和“開始比對”功能的核心部分。 一、功能簡介 我們將聚焦兩個核心功能&…

volatile關鍵字用途說明

volatile 關鍵字在 C# 中用于指示編譯器和運行時系統&#xff0c;某個字段可能會被多個線程同時訪問&#xff0c;并且該字段的讀寫操作不應被優化&#xff08;例如緩存到寄存器或重排序&#xff09;&#xff0c;以確保所有線程都能看到最新的值。這使得 volatile 成為一種輕量級…

【區塊鏈安全 | 第三十五篇】溢出漏洞

文章目錄 溢出上溢示例溢出漏洞溢出示例漏洞代碼代碼審計1. deposit 函數2. increaseLockTime 函數 攻擊代碼攻擊過程總結修復建議審計思路 溢出 算術溢出&#xff08;Arithmetic Overflow&#xff09;&#xff0c;簡稱溢出&#xff08;Overflow&#xff09;&#xff0c;通常分…

百度的deepseek與硅基模型的差距。

問題&#xff1a; 已經下載速度8兆每秒&#xff0c;請問下載30G的文件需要多長時間&#xff1f; 關于這個問題。百度的回答如下&#xff1a; ?30GB文件下載時間計算? ?理論計算?&#xff08;基于十進制單位&#xff09;&#xff1a; ?單位換算? 文件大小&#xff1a;3…

車載診斷架構 --- 特殊定義NRC處理原理

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 周末洗了一個澡,換了一身衣服,出了門卻不知道去哪兒,不知道去找誰,漫無目的走著,大概這就是成年人最深的孤獨吧! 舊人不知我近況,新人不知我過…

面試題ing

1、js中set和map的作用和區別? 在 JavaScript 中&#xff0c;Set 和 Map 是兩種非常重要的集合類型 1、Set 是一種集合數據結構&#xff0c;用于存儲唯一值。它類似于數組&#xff0c;但成員的值都是唯一的&#xff0c;沒有重復的值。Set 中的值只能是唯一的&#xff0c;任何…

Python爬蟲第6節-requests庫的基本用法

目錄 前言 一、準備工作 二、實例引入 三、GET請求 3.1 基本示例 3.2 抓取網頁 3.3 抓取二進制數據 3.4 添加headers 四、POST請求 五、響應 前言 前面我們學習了urllib的基礎使用方法。不過&#xff0c;urllib在實際應用中存在一些不便之處。以網頁驗證和Cookies處理…

Go 學習筆記 · 進階篇 · 第一天:接口與多態

&#x1f436;Go接口與多態&#xff1a;繼承沒了&#xff0c;但自由炸裂&#xff01; 最近翻 Go 的代碼&#xff0c;突然看到這么一段&#xff1a; type Animal interface {Speak() string }我一愣&#xff0c;咦&#xff1f;這不就是 Java 里常見的“接口”嗎&#xff1f; …

信息學奧賽一本通 1929:【04NOIP普及組】火星人 | 洛谷 P1088 [NOIP 2004 普及組] 火星人

【題目鏈接】 ybt 1929&#xff1a;【04NOIP普及組】火星人 洛谷 P1088 [NOIP 2004 普及組] 火星人 【題目考點】 1. 深搜回溯 2. STL next_permutation函數 頭文件<algorithm> 函數定義&#xff1a;next_permutation(lb, ub, cmp) lb&#xff1a;區間下界&#xff…

借助 AI 工具使用 Python 實現北京市店鋪分布地理信息可視化教程

一、項目概述 本項目通過 Python 的pyecharts庫&#xff0c;結合 AI 工具輔助代碼編寫與邏輯梳理&#xff0c;實現北京市店鋪數量分布及區域連線的地理信息可視化&#xff0c;最終生成交互式地圖圖表。 二、準備工作 1. 環境與工具 Python 環境&#xff1a;確保已安裝 Pyth…

Python項目打包指南:PyInstaller與SeleniumWire的兼容性挑戰及解決方案

前言 前段時間做一個內網開發的需求&#xff0c;要求將selenium程序打包成.exe放在內網的win7上運行&#xff0c;在掘金搜了一圈也沒有發現相關文章&#xff0c;因此將過程中踩到的坑記錄分享一下。 本文涵蓋了具體打包操作、不同模塊和依賴項的兼容性解決方案&#xff0c;以…

(一)棧結構、隊列結構

01-線性結構-數組-棧結構 線性結構&#xff08;Linear List)是由n&#xff08;n>0)個數據元素&#xff08;結點&#xff09; a[0], a[1], a[2], a[3],...,a[n-1]組成的有限序列 數組 通常數組的內存是連續的&#xff0c;所以在知道數組下標的情況下&#xff0c;訪問效率是…

【學Rust寫CAD】35 alpha_mul_256(alpha256.rs補充方法)

源碼 // Calculates (value * alpha256) / 255 in range [0,256], // for [0,255] value and [0,256] alpha256. pub fn alpha_mul_256(self,value: u32) -> Alpha256 {let prod value * self.0;Alpha256((prod (prod >> 8)) >> 8) }代碼分析 這個函數 alph…

C# 與 相機連接

一、通過組件連接相機 需要提前在VisionPro里面保存一個CogAcqFifoTool相機工具為 .vpp 定義一個相機工具 CogAcqFifoTool mAcq null;將保存的相機工具放入mAcq中 string path “C:\Acq.vpp”; mAcq (CogAcqFifoTool)CogSerializer.LoadObjectFrommFile(path);給窗口相機…

Java并發編程高頻面試題

一、基礎概念 1. 并行與并發的區別&#xff1f; 并行&#xff1a;多個任務在多個CPU核心上同時執行&#xff08;物理上同時&#xff09;。并發&#xff1a;多個任務在單CPU核心上交替執行&#xff08;邏輯上同時&#xff09;。類比&#xff1a;并行是多個窗口同時服務&#x…