Day60--圖論--94. 城市間貨物運輸 I(卡碼網),95. 城市間貨物運輸 II(卡碼網),96. 城市間貨物運輸 III(卡碼網)

Day60–圖論–94. 城市間貨物運輸 I(卡碼網),95. 城市間貨物運輸 II(卡碼網),96. 城市間貨物運輸 III(卡碼網)

今天是Bellman_ford專場。帶你從普通的Bellman_ford,到隊列優化的Bellman_ford(SPFA算法),到使用Bellman_ford解決負權回路問題,和使用Bellman_ford解決單源有限最短回路問題。

總共3道題目,六種做法。

94. 城市間貨物運輸 I(卡碼網)

Bellman_ford算法的核心思想是 對所有邊進行松弛n-1次操作(n為節點數量),從而求得目標最短路

其實 Bellman_ford算法 也是采用了動態規劃的思想,即:將一個問題分解成多個決策階段,通過狀態之間的遞歸關系最后計算出全局最優解。

Bellman_ford 是可以計算 負權值的單源最短路算法。

其算法核心思路是對 所有邊進行 n-1 次 松弛。

方法:Bellman_ford

思路:

核心思路代碼:

if (minDist[e.to] > minDist[e.from] + e.val) minDist[e.to] = minDist[e.from] + e.val;

如果改一改樣子,是不是跟動態規劃很像呢?

minDist[B] = min(minDist[A] + value, minDist[B])

其實松弛操作,就是進行“動態規劃”。因為每更新一個節點的狀態,都會影響其它節點。

所以每更新一個節點,就對全部節點的狀態進行更新。(n個節點,更新n-1一次)

實際上,每更新一個節點,并不一定要更新全部節點的minDist。所以下面會講到優化的方式。

import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<Edge> edges = new ArrayList<>();// 將所有邊保存起來for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();edges.add(new Edge(from, to, val));}int start = 1; // 起點int end = n; // 終點int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;// 對所有邊 松弛 n-1 次(這里遍歷的是節點,從1遍歷到n-1)for (int i = 1; i < n; i++) {// 每一次松弛,都是對所有邊進行松弛for (Edge e : edges) {// 松弛操作if (minDist[e.from] != Integer.MAX_VALUE&& minDist[e.to] > minDist[e.from] + e.val) {minDist[e.to] = minDist[e.from] + e.val;}}}// 不能到達終點if (minDist[end] == Integer.MAX_VALUE) {System.out.println("unconnected");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

不用隊列優化的時候,一旦一個節點更新了,就要刷新整個圖的所有節點的minDist,但是這樣有很多操作是多余的。比如節點1只和2,3相連,就應該只刷新2,3的midDist。我們用隊列記錄“要刷新的節點”,可以減少很多操作。

但是隊列的入隊和出隊也是有性能損耗的,如果是稠密圖,邊比較多,而且互相連接的節點比較多的話,隊列帶來的性能損耗可能會超過原來遍歷節點的損耗。

故此,稀疏圖適合用隊列優化,稠密圖的話,隊列優化效果不明顯,加上隊列操作,還甚至有可能比不優化更加耗時。

方法: 隊列優化的 Bellman_ford(又名SPFA)

思路:

  1. 不優化時,由于要遍歷所有的邊,所以直接將所有的邊存起來就好:List<Edge> edges = new ArrayList<>();;隊列優化時,需要用鄰接表保存圖,不然每次就要遍歷找起點from對應的邊了。
  2. 隊列記錄,“要刷新的節點”,該節點需要poll出來處理,它所有鄰接的節點的minDist
  3. boolean[] isInQue記錄在隊列,已經在隊列的不要重復添加。
import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<List<Edge>> graph = new ArrayList<>();for (int i = 0; i <= n; i++) {graph.add(new ArrayList<>());}// 鄰接表保存圖for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();graph.get(from).add(new Edge(from, to, val));}int start = 1; // 起點int end = n; // 終點// 存儲從源點到每個節點的最短距離int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;// 隊列記錄,“要刷新的節點”,該節點需要poll出來處理,它所有鄰接的節點的minDistDeque<Integer> que = new ArrayDeque<>();que.offer(start);// 在隊列標志boolean[] isInQue = new boolean[n + 1];while (!que.isEmpty()) {int cur = que.poll();isInQue[cur] = false;for (Edge e : graph.get(cur)) {// 松弛操作if (minDist[e.to] > minDist[e.from] + e.val) {minDist[e.to] = minDist[e.from] + e.val;// 避免重復入隊if (!isInQue[e.to]) {que.offer(e.to);isInQue[e.to] = true;}}}}// 不能到達終點if (minDist[end] == Integer.MAX_VALUE) {System.out.println("unconnected");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

95. 城市間貨物運輸 II(卡碼網)

方法:bellman_ford之判斷負權回路

思路:

負權回路的意思:出現環,每走一次環,得出的sum是負數。因為求的是最小值min,所以會一直在這個環轉圈圈。

在 bellman_ford 算法中,松弛 n-1 次所有的邊 就可以求得 起點到任何節點的最短路徑,松弛 n 次以上,minDist數組(記錄起到到其他節點的最短距離)中的結果也不會有改變

而本題有負權回路的情況下,一直都會有更短的最短路,所以 松弛 第n次,minDist數組 也會發生改變。

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

import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<Edge> edges = new ArrayList<>();for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();edges.add(new Edge(from, to, val));}int start = 1;int end = n;int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;// 這里我們松弛n次,最后一次判斷負權回路boolean circle = false;for (int i = 1; i <= n; i++) {for (Edge e : edges) {if (i < n) {// 照常if (minDist[e.from] != Integer.MAX_VALUE&& minDist[e.to] > minDist[e.from] + e.val) {minDist[e.to] = minDist[e.from] + e.val;}} else {// 多加一次松弛判斷負權回路if (minDist[e.from] != Integer.MAX_VALUE&& minDist[e.to] > minDist[e.from] + e.val) {circle = true;}}}}// 出現負權回路,轉圈圈。if (circle) {System.out.println("circle");} else if (minDist[end] == Integer.MAX_VALUE) {// 不能到達終點System.out.println("unconnected");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

方法: 隊列優化的 Bellman_ford(又名SPFA)

思路:

思路同上,統計是否有節點,遍歷過n次。

如果有,證明存在負權回路,在轉圈圈了,此時,清空隊列,退出循環。

import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<List<Edge>> graph = new ArrayList<>();for (int i = 0; i <= n; i++) {graph.add(new ArrayList<>());}for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();graph.get(from).add(new Edge(from, to, val));}int start = 1;int end = n;int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;Deque<Integer> que = new ArrayDeque<>();que.offer(start);boolean[] isInQue = new boolean[n + 1];// 統計該節點,入隊的次數int[] countInQue = new int[n + 1];countInQue[start]++;// 是否存在負權回路,轉圈圈的標志boolean circle = false;while (!que.isEmpty()) {int cur = que.poll();isInQue[cur] = false;for (Edge e : graph.get(cur)) {if (minDist[e.to] > minDist[e.from] + e.val) {minDist[e.to] = minDist[e.from] + e.val;// 避免重復入隊if (!isInQue[e.to]) {que.offer(e.to);isInQue[e.to] = true;// 入隊次數+1countInQue[e.to]++;}// 如果有節點入隊n次,證明已經開始轉圈圈,清空隊列,退出循環if (countInQue[e.to] == n) {circle = true;que.clear();break;}}}}// 出現負權回路,轉圈圈。if (circle) {System.out.println("circle");} else if (minDist[end] == Integer.MAX_VALUE) {// 不能到達終點System.out.println("unconnected");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

96. 城市間貨物運輸 III(卡碼網)

其關鍵在于本題的兩個因素:

  • 本題可以有負權回路,說明只要多做松弛,結果是會變的。
  • 本題要求最多經過k個節點,對松弛次數是有限制的。

方法:bellman_ford之單源有限最短路

思路:

最多經過k座城市,加上start和end,就是一共有k+2個城市。所以要遍歷k+1次。

使用minDistCopy記錄上一輪遍歷的結果。

import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<Edge> edges = new ArrayList<>();for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();edges.add(new Edge(from, to, val));}int start = in.nextInt();int end = in.nextInt();// 最多經過k座城市,加上start和end,就是一共有k+2個城市int k = in.nextInt();int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;// 用來記錄上一輪遍歷的結果int[] minDistCopy = new int[n + 1];// 一共有k+2個城市,所以要遍歷k+1遍for (int i = 1; i <= k + 1; i++) {// 復制上一輪遍歷的結果System.arraycopy(minDist, 0, minDistCopy, 0, n + 1);for (Edge e : edges) {if (minDistCopy[e.from] != Integer.MAX_VALUE&& minDist[e.to] > minDistCopy[e.from] + e.val) {minDist[e.to] = minDistCopy[e.from] + e.val;}}}if (minDist[end] == Integer.MAX_VALUE) {// 不能到達終點System.out.println("unreachable");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

方法: 隊列優化的 Bellman_ford(又名SPFA)

思路:

關鍵在于 如何控制松弛k次。可以用一個變量 que_size 記錄每一輪松弛入隊列的所有節點數量。

下一輪松弛的時候,就把隊列里 que_size 個節點都彈出來,就是上一輪松弛入隊列的節點。

import java.util.*;public class Main {static class Edge {int from;int to;int val;public Edge(int from, int to, int val) {this.from = from;this.to = to;this.val = val;}}public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();List<List<Edge>> graph = new ArrayList<>();for (int i = 0; i <= n; i++) {graph.add(new ArrayList<>());}for (int i = 0; i < m; i++) {int from = in.nextInt();int to = in.nextInt();int val = in.nextInt();graph.get(from).add(new Edge(from, to, val));}int start = in.nextInt();int end = in.nextInt();// 最多經過k座城市,加上start和end,就是一共有k+2個城市int k = in.nextInt();// 原來要遍歷n-1次,現在有k+2個節點,所以要遍歷k+1次k++;int[] minDist = new int[n + 1];Arrays.fill(minDist, Integer.MAX_VALUE);minDist[start] = 0;// 用來記錄上一輪遍歷的結果int[] minDistCopy = new int[n + 1];Deque<Integer> que = new ArrayDeque<>();que.offer(start);int queSize = 0;while (k-- > 0 && !que.isEmpty()) {// isInQue標志,每一輪都要初始化一次boolean[] isInQue = new boolean[n + 1];// 復制上一輪遍歷的結果System.arraycopy(minDist, 0, minDistCopy, 0, n + 1);// 這一輪要松弛的個數queSize = que.size();// 開始這一輪while (queSize-- > 0) {int cur = que.poll();isInQue[cur] = false;for (Edge e : graph.get(cur)) {if (minDist[e.to] > minDistCopy[e.from] + e.val) {minDist[e.to] = minDistCopy[e.from] + e.val;if (!isInQue[e.to]) {que.offer(e.to);isInQue[e.to] = true;}}}}}// 不能到達終點if (minDist[end] == Integer.MAX_VALUE) {System.out.println("unreachable");} else {// 到達終點最短路徑(運輸成本最小)System.out.println(minDist[end]);}}
}

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

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

相關文章

Jenkins服務器SSH公鑰配置步驟

步驟1. 在Jenkins服務器上生成SSH密鑰在Jenkins服務器上執行以下命令&#xff1a;# 1. 生成SSH密鑰對 ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N ""# 2. 設置正確的權限 chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa chmod 644 ~/.ssh/id_rsa.pub# 3. 查看公鑰內…

數據鏈路層-網絡層-傳輸層

文章目錄深入淺出理解網絡核心&#xff1a;從交換機到TCP/UDP一、數據鏈路層&#xff1a;交換機的"地盤"1. 數據鏈路層的核心功能2. 以太網的發展歷程3. 以太網中的MAC地址4. 以太網幀格式&#xff1a;數據的"快遞包裝"5. 交換機的工作原理&#xff1a;高效…

專題:2025跨境電商市場布局、供應鏈與產業帶賦能報告 |附130+份報告PDF、原數據表匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p43616 2025年&#xff0c;跨境圈的老板們集體焦慮&#xff1a;美國關稅飆到145%&#xff0c;亞馬遜封號潮卷土重來&#xff0c;而東南亞卻悄悄漲了246%&#xff01;這不是危言聳聽——66%的美國消費者說&#xff0c;海外貨漲10%就換本…

LINUX 818 shell:random;for for

問題 [rootweb ~]# a$(echo $[$RANDOM%10]) 您在 /var/spool/mail/root 中有郵件 [rootweb ~]# echo $a 3 [rootweb ~]# echo 139$a$a$a$a$a$a$a$a 13933333333 您在 /var/spool/mail/root 中有郵件 [rootweb ~]# echo 139 $a 139 3 [rootweb ~]# echo $a 3 [rootweb ~]# echo …

JavaScript 原型機制詳解:從概念到實戰(附個人學習方法)

原型是 JavaScript 實現繼承與代碼復用的核心機制,也是面試高頻考點。本文結合個人學習經驗、核心概念解析與實戰案例,幫你徹底搞懂原型、prototype、__proto__ 及相關知識點,同時分享高效的學習方法。 一、個人學習方法:高效掌握復雜知識點 復雜概念(如原型)的學習,關…

【人工智能】2025年AI代理失控危機:構建安全壁壘,守護智能未來

還在為高昂的AI開發成本發愁?這本書教你如何在個人電腦上引爆DeepSeek的澎湃算力! 在2025年,AI代理(AI Agents)已成為日常生活和企業運營的核心組成部分,它們能夠自主決策、執行任務并與環境互動。然而,隨著AI代理能力的指數級提升,其安全隱患也日益凸顯,包括數據泄露…

從噪聲到動作:Diffusion Policy 如何改變機器人學習?

從噪聲到動作&#xff1a;Diffusion Policy 如何改變機器人學習&#xff1f; 引言 在機器人手臂操作方面一直存在諸多挑戰。我們熟悉的工業場景中的組裝機械臂&#xff0c;往往依賴于寫死的程序指令進行控制&#xff0c;具有高度規范化與高精度的特點。而當機械臂需要在復雜、…

量子計算和超級計算機將徹底改變技術

我們生活在技術時代&#xff0c;但未來仍有無限可能。近年來&#xff0c;各大企業在量子計算領域持續邁出雖小卻關鍵的步伐 —— 這一技術注定將徹底改變我們所熟知的世界。以下精選的潛在應用場景&#xff0c;將對從交通出行到醫療健康的多個領域產生深遠影響。 在由 “1” 和…

Linux 中文顯示空白框(Java)

問題展示&#xff1a;解決方案本系統采用宋體&#xff0c;若是其它字體&#xff0c;可以類似排查Font rewardFirstFont new Font("SimSun", Font.BOLD, 20);linux系統字體-檢查查詢linux系統所有字體fc-list檢查是否有目標字體&#xff08;SimSun&#xff09;&#…

普通用戶使用docker命令

參考大佬 https://blog.51cto.com/u_16175448/12082279 詳細步驟及代碼 步驟 1&#xff1a;安裝 Docker 首先&#xff0c;你需要安裝 Docker。 步驟 2&#xff1a;創建 Docker 用戶組 Docker 默認以 root 用戶運行&#xff0c;為了普通用戶能夠使用 Docker&#xff0c;我們需要…

【傳奇開心果系列】Flet框架實現的家庭記賬本示例自定義模板

Flet家庭記賬本示例自定義模板一、效果展示截圖二、Flet家庭記賬本概況介紹三、應用特色1. 簡潔直觀的用戶界面2. 全面的財務管理功能3. 實時數據監控4. 數據可視化分析5. 數據管理功能四、使用場景個人財務管理家庭賬務管理小微企業記賬學生理財教育五、主要功能模塊&#xff…

Node.js 在 Windows Server 上的離線部署方案

Node.js 在 Windows Server 上的離線部署方案 離線部署的核心是提前準備所有依賴資源&#xff08;避免在線下載&#xff09;&#xff0c;并通過本地配置完成服務搭建&#xff0c;整體分為「依賴準備」「環境配置」「項目部署」「服務注冊」4個階段。 一、提前準備離線資源&am…

SpringAI接入openAI配置出現的問題全解析

SpringAI接入openAI配置出現的四個問題全解析1、無法下載openAI或SpringAI依賴包1.1、思路就是從哪個源下載所需的依賴包1.2、解決思路&#xff1a;我們可以看阿里的中央倉庫是否有集成SpringAI的依賴&#xff0c;從它這里下也是可以的。我們看看阿里云云效maven地址&#xff0…

自然語言處理——02 文本預處理(上)

1 認識文本預處理 概念&#xff1a; 文本語料在輸送給模型前一般需要一系列的預處理工作&#xff0c;才能符合模型輸入的要求&#xff1b;比如&#xff1a;將文本轉化成模型需要的張量、規范張量的尺寸&#xff1b;比如&#xff1a; 關于數據X&#xff1a;數據有沒有臟數據、數…

數據結構:二叉樹的鏈式存儲

用鏈表來表示一棵二叉樹&#xff0c;即用指針指向來指示元素的邏輯關系。通常的方法是鏈表中每個結點由三個域組成&#xff0c;數據域和左右指針域&#xff0c;左右指針分別用來給出該結點左孩子和右孩子所在的鏈結點的存儲地址 。 我們之前就已經說過&#xff0c;二叉樹是遞歸…

【Spring Boot把日志記錄到文件里面】

<?xml version"1.0" encoding"UTF-8"?> <configuration><!-- 日志輸出格式 --><property name"LOG_PATTERN" value"%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n" /><!-- 日志…

大數據服務完全分布式部署- 其他組件(阿里云版)

ZooKeeper 安裝 官網 解壓 cd /export/server/ tar -zxvf /export/server/apache-zookeeper-3.9.3-bin.tar.gz -C /export/server/軟鏈接 ln -s /export/server/apache-zookeeper-3.9.3-bin /export/server/zookeeper配置 cd /export/server/zookeeper/ mkdir zkDatamyid…

Windows 平板/電腦 上使用 DHCPSRV 搭建 DHCP 服務器

一、DHCPSRV 核心優勢 輕量便攜:單文件綠色軟件,無需安裝 全圖形界面:比命令行工具更友好 支持IPv4/IPv6:滿足現代網絡需求 低資源占用:適合平板電腦運行(內存<10MB) 租約管理:可查看實時IP分配情況 二、超詳細配置流程 1. 下載與初始化 官網下載:http://www…

ArcGIS動態表格批量出圖

前言&#xff1a;產品介紹&#xff1a;ArcGIS動態表格擴展模塊Mapping and Charting Solutions&#xff0c;可用于插入動態表格&#xff0c;與數據驅動結合&#xff0c;出圖效率無敵。注&#xff1a;優先選擇arcgis10.2.2。 一、首先是根據自身攜帶的arcgis數據進行下載對應的…

Linux小白加油站,第三周周考

1.如何查看當前系統中所有磁盤設備及其分區結構(如磁盤名稱、大小、掛載點等)? lsblk # 顯示磁盤名稱、大小、掛載點&#xff08;P21&#xff09;2.若需對空閑磁盤(如/dev/sdb)進行交互式劃分&#xff0c;如何進入操作界面并創建一個5GB的主分區(類型為Linux默認文件系統)? …