最短路径算法:Bellman-Ford算法
引言
在图论中,Bellman-Ford算法是一种用于计算单源最短路径的算法。与Dijkstra算法不同,Bellman-Ford算法可以处理带有负权边的图,并且可以检测图中是否存在负权环。本文将详细介绍Bellman-Ford算法的定义、步骤及其实现。
Bellman-Ford算法
定义
Bellman-Ford算法是一种用于计算从源顶点到图中所有其他顶点的最短路径的算法。该算法可以处理带有负权边的图,并且可以检测是否存在负权环。
算法步骤
- 初始化:设定源顶点的距离为0,其余顶点的距离为正无穷大。
- 松弛操作:对所有边进行(V-1)次松弛操作,其中(V)是顶点的数量。对于每条边(u, v),如果
dist[u] + weight < dist[v],则更新dist[v] = dist[u] + weight。 - 检查负权环:对所有边进行一次检查,如果发现仍然可以进行松弛操作,则说明图中存在负权环。
示例
假设我们有一个带权有向图,顶点集合为 ({A, B, C, D, E}),边和权重集合为 ({(A, B, -1), (A, C, 4), (B, C, 3), (B, D, 2), (B, E, 2), (D, B, 1), (D, C, 5), (E, D, -3)})。
Bellman-Ford算法图解
步骤1:初始化
将源顶点A的距离设为0,其余顶点的距离设为正无穷大。
顶点: A B C D E
距离: 0 ∞ ∞ ∞ ∞
步骤2:第一次松弛操作
对每条边进行松弛操作:
- 对于边 (A, B, -1):更新 B 的距离为 -1。
- 对于边 (A, C, 4):更新 C 的距离为 4。
- 对于边 (B, C, 3):更新 C 的距离为 2。
- 对于边 (B, D, 2):更新 D 的距离为 1。
- 对于边 (B, E, 2):更新 E 的距离为 1。
- 对于边 (D, B, 1):不更新 B 的距离。
- 对于边 (D, C, 5):不更新 C 的距离。
- 对于边 (E, D, -3):更新 D 的距离为 -2。
顶点: A B C D E
距离: 0 -1 2 -2 1
步骤3:第二次松弛操作
对每条边再次进行松弛操作:
- 对于边 (A, B, -1):不更新 B 的距离。
- 对于边 (A, C, 4):不更新 C 的距离。
- 对于边 (B, C, 3):不更新 C 的距离。
- 对于边 (B, D, 2):不更新 D 的距离。
- 对于边 (B, E, 2):不更新 E 的距离。
- 对于边 (D, B, 1):不更新 B 的距离。
- 对于边 (D, C, 5):不更新 C 的距离。
- 对于边 (E, D, -3):不更新 D 的距离。
顶点: A B C D E
距离: 0 -1 2 -2 1
步骤4:检查负权环
对每条边进行一次检查,如果发现仍然可以进行松弛操作,则说明图中存在负权环。在此示例中,没有发现负权环。
Bellman-Ford算法实现
下面是用Java实现Bellman-Ford算法的代码示例:
import java.util.Arrays;public class BellmanFordAlgorithm {private int vertices; // 顶点数量private int[][] edges; // 边数组,包含边的起点、终点和权重private int edgeCount; // 边数量public BellmanFordAlgorithm(int vertices, int edgeCount) {this.vertices = vertices;this.edgeCount = edgeCount;edges = new int[edgeCount][3];}// 添加边public void addEdge(int edgeIndex, int src, int dest, int weight) {edges[edgeIndex][0] = src;edges[edgeIndex][1] = dest;edges[edgeIndex][2] = weight;}// 计算从源顶点到所有顶点的最短路径public void bellmanFord(int src) {int[] dist = new int[vertices]; // 最短距离数组Arrays.fill(dist, Integer.MAX_VALUE);dist[src] = 0;// 对所有边进行 V-1 次松弛操作for (int i = 1; i < vertices; i++) {for (int j = 0; j < edgeCount; j++) {int u = edges[j][0];int v = edges[j][1];int weight = edges[j][2];if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {dist[v] = dist[u] + weight;}}}// 检查是否存在负权环for (int j = 0; j < edgeCount; j++) {int u = edges[j][0];int v = edges[j][1];int weight = edges[j][2];if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {System.out.println("图中存在负权环");return;}}printSolution(dist);}// 打印最短路径private void printSolution(int[] dist) {System.out.println("顶点\t距离源顶点");for (int i = 0; i < vertices; i++) {System.out.println(i + "\t\t" + dist[i]);}}public static void main(String[] args) {int vertices = 5;int edgeCount = 8;BellmanFordAlgorithm graph = new BellmanFordAlgorithm(vertices, edgeCount);graph.addEdge(0, 0, 1, -1);graph.addEdge(1, 0, 2, 4);graph.addEdge(2, 1, 2, 3);graph.addEdge(3, 1, 3, 2);graph.addEdge(4, 1, 4, 2);graph.addEdge(5, 3, 1, 1);graph.addEdge(6, 3, 2, 5);graph.addEdge(7, 4, 3, -3);graph.bellmanFord(0); // 从顶点0开始计算最短路径}
}
代码注释
-
类和构造函数:
public class BellmanFordAlgorithm {private int vertices; // 顶点数量private int[][] edges; // 边数组,包含边的起点、终点和权重private int edgeCount; // 边数量public BellmanFordAlgorithm(int vertices, int edgeCount) {this.vertices = vertices;this.edgeCount = edgeCount;edges = new int[edgeCount][3];}BellmanFordAlgorithm类包含图的顶点数量和边数组,并有一个构造函数来初始化这些变量。 -
添加边:
public void addEdge(int edgeIndex, int src, int dest, int weight) {edges[edgeIndex][0] = src;edges[edgeIndex][1] = dest;edges[edgeIndex][2] = weight; }addEdge方法用于向图中添加边。 -
Bellman-Ford算法:
public void bellmanFord(int src) {int[] dist = new int[vertices]; // 最短距离数组Arrays.fill(dist, Integer.MAX_VALUE);dist[src] = 0;// 对所有边进行 V-1 次松弛操作for (int i = 1; i < vertices; i++) {for (int j = 0; j < edgeCount; j++) {int u = edges[j][0];int v = edges[j][1];int weight = edges[j][2];if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {dist[v] = dist[u] + weight;}}}// 检查是否存在负权环for (int j = 0; j < edgeCount; j++) {int u = edges[j][0];int v = edges[j][1];int weight = edges[j][2];if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {System.out.println("图中存在负权环");return;}}printSolution(dist); }bellmanFord方法实现了Bellman-Ford算法,计算从源顶点到所有其他顶点的最短路径,并检测是否存在负权环。 -
打印最短路径:
private void printSolution(int[] dist) {System.out.println("顶点\t距离源顶点");for (int i = 0; i < vertices; i++) {System.out.println(i + "\t\t" + dist[i]);} }printSolution方法用于打印最短路径。
结论
通过上述讲解和实例代码,我们详细展示了Bellman-Ford算法的定义、步骤及其实现。Bellman-Ford算法是一种重要的最短路径算法,特别适用于带有负权边的图,并且可以检测负权环。希望这篇博客对您有所帮助!
如果您觉得这篇文章对您有帮助,请关注我的CSDN博客,点赞并收藏这篇文章,您的支持是我持续创作的动力!
关键内容总结:
- Bellman-Ford算法的定义
- Bellman-Ford算法的步骤
- Bellman-Ford算法的实现及其代码注释
推荐阅读:深入探索设计模式专栏,详细讲解各种设计模式的应用和优化。点击查看:深入探索设计模式。
特别推荐:设计模式实战专栏,深入解析设计模式的实际应用,提升您的编程技巧。点击查看:设计模式实战。
如有任何疑问或建议,欢迎在评论区留言讨论。谢谢阅读!
相关文章:
最短路径算法:Bellman-Ford算法
引言 在图论中,Bellman-Ford算法是一种用于计算单源最短路径的算法。与Dijkstra算法不同,Bellman-Ford算法可以处理带有负权边的图,并且可以检测图中是否存在负权环。本文将详细介绍Bellman-Ford算法的定义、步骤及其实现。 Bellman-Ford算…...
爬虫:xpath模块及昵图网实例
xpath模块 from lxml import etreestr1 """ <div><ul><li class"item-0"><a href"link1.html">first item</a></li><li class"item-1"><a href"link2.html">second…...
高级java每日一道面试题-2024年8月03日-web篇-forward和redirect有什么区别?
如果有遗漏,评论区告诉我进行补充 面试官: forward和redirect有什么区别? 我回答: 在Java Web开发中,forward和redirect是Servlet容器提供的两种用于页面跳转的技术。它们的主要区别在于客户端感知的方式、URL地址的变化、请求对象的共享等方面。下面详细介绍两…...
如何让你的网站拥有更好的体验
在HTML中,属性是用于提供关于HTML元素的额外信息。接下来我们将讲解13个可以让用户拥有更好体验的HTML属性。 Accept 属性 我们可以在<input>元素(仅适用于文件类型)中使用accept属性来指定服务器可以接受的文件类型。 <input ty…...
opencascade AIS_TypeFilter AIS_XRTrackedDevice源码学习
opencascade AIS_TypeFilter 前言 通过它们的类型选择交互对象。该过滤器会对本地上下文中的每个交互对象提出问题, 以确定它是否具有非空的所有者,并且如果是,则检查它是否是所需类型。 如果对象在每种情况下都返回 true,则保留…...
使用Spring AOP监控指定方法执行时间
文章目录 一、加入pom依赖二、切面类和注解三、执行方法 一、加入pom依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>二、切面类和注解 import java.lang.…...
最新CSS3纵向菜单的实现
纵向菜单 通过下面例子,你会知道把列表转换成菜单的关键技术 a中的#是URL的占位符可以点击,真正用途中写实际URL <nav class"list1"><ul><li><a href"#">Alternative</a></li><li><…...
GooLeNet模型搭建
一、model import torch from torch import nn from torchsummary import summaryclass Inception(nn.Module):def __init__(self, in_channels, c1, c2 , c3 , c4):super(Inception, self).__init__()self.ReLU nn.ReLU()#路线1:1x1卷积self.p1_1 nn.Conv2d(in_channels i…...
使用ThreadLocal来存取单线程内的数据
一.什么是ThreadLocal? ThreadLocal,即线程本地变量。如果你创建了一个 ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地拷贝,多个线程操作这个变量的时候,实际是在操作自己本地内存里面的变量&…...
elasticsearch教程
1. 单点部署(rpm): #提前关闭firewalld,否则无法组建集群 #1. 下载ES rpm包 ]# https://www.elastic.co/cn/downloads #2. 安装es ]# rpm -ivh elasticsearch-7.17.5-x86_64.rpm #3. 调整内核参数(太低的话es会启动报错) echo "vm.max_map_count655360 fs.file-max 655…...
Arrays、Lambda表达式、Collection集合
1. Arrays 1.1 操作数组的工具类 方法名说明public static String toString(数组)把数组拼接成一个字符串public static int binarySearch(数组,查找的元素)二分查找法查找元素public static int[] copyOf(原数组,新数组长度)拷贝数组public static int[] copyOfRange(原数组…...
2024年前端趋势:全栈或许是不容错过的选择!
近年来,前端开发的技术不断推陈出新,2024年也不例外。在这个变化迅速的领域,全栈开发逐渐成为一股不容忽视的趋势。无论你是经验丰富的开发者,还是刚刚入门的新手,掌握全栈技术都能让你在竞争中脱颖而出。而在这个过程…...
MySQL 实战 45 讲(01-05)
本文为笔者学习林晓斌老师《MySQL 实战 45 讲》课程的学习笔记,并进行了一定的知识扩充。 sql 查询语句的执行流程 大体来说,MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层包括连接器、查询缓存、分析器、优化器和执行器。 连接器负责接收客…...
仓颉编程语言入门 -- Array数组详解
仓颉编程语言入门 – Array数组详解 一. 如何创建Array数组 我们可以使用 Array 类型来构造单一元素类型,有序序列的数据。 1.仓颉使用 Array 来表示 Array 类型。T 表示 Array 的元素类型,T 可以是任意类型 , 类似于泛型的概念 var arr:Array<St…...
C#初级——简单单例模式使用
单例模式 单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例,通过单例模式防止私有成员被多次引用,防止数据被随意纂改。本文使用的是线程不安全的懒汉式单例。 创建单例模式 首…...
2024.07.29 校招 实习 内推 面经
地/球🌍 : neituijunsir 交* 流*裙 ,内推/实习/校招汇总表格 1、校招 | 美/团// 快驴、小象、优/选/事/业/部2024年校/园/招聘(内推) 校招 | 美团快驴、小象、优选事业部2024年校园招聘(内推ÿ…...
速盾:爬虫攻击和cc攻击的区别是什么?
爬虫攻击和CC(Distributed Denial of Service)攻击是网络安全领域两种不同类型的攻击方式。尽管它们都涉及对目标网站或服务器的非法访问,但它们的目的、方法和影响各不相同。在接下来的文章中,我们将详细介绍这两种攻击方式的区别…...
Tomcat与Nginx的区别详解
目录 引言Tomcat概述 Tomcat的历史Tomcat的架构Tomcat的功能Nginx概述 Nginx的历史Nginx的架构Nginx的功能Tomcat与Nginx的区别 架构上的区别...
【大模型从入门到精通5】openAI API高级内容审核-1
这里写目录标题 高级内容审核利用 OpenAI 内容审核 API 的高级内容审核技术整合与实施使用自定义规则增强审核综合示例防止提示注入的策略使用分隔符隔离命令理解分隔符使用分隔符实现命令隔离 高级内容审核 利用 OpenAI 内容审核 API 的高级内容审核技术 OpenAI 内容审核 AP…...
JVM系列 | 对象的消亡3——垃圾收集器的对比与实现细节
垃圾收集器 文章目录 各收集器简单对比收集器启动参数各收集器详细说明JDK 1.3 之前JDK 1.3 | SerialJDK 1.4 | ParNewJDK 1.4 | Parallel ScavengeJDK 5 | CMS 收集器JDK 7 | G1 各收集器简单对比 收集器名称出现时间淘汰时间目标采用技术线程数STW分代备注无名JDK 1.3之前JD…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...
