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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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默认文件系统)? …