C++: 实现贝尔曼-福特算法以查找最短距离 从给定节点到有向图中的所有其他节点,其 边已被指定为实值长度(附带源码)

项目背景详细介绍

在图论与算法设计中,最短路径问题是最基础、也是最重要的问题之一。给定一个带权图以及一个起始节点,我们希望计算:

从给定起点到图中所有其他节点的最短距离。

在很多经典教材和工程实践中,大家最熟悉的可能是 Dijkstra 算法。然而,Dijkstra 算法有一个非常重要的限制:

  • 边权必须是非负的

一旦图中存在负权边(例如在金融套利、能量模型、约束优化等问题中),Dijkstra 将不再适用。

此时,**贝尔曼-福特算法(Bellman–Ford Algorithm)**就成为了标准选择。

贝尔曼-福特算法具有以下显著特点:

  • 支持 实值边权(包括负数)
  • 能够检测 负权环(Negative Cycle)
  • 算法原理清晰,非常适合教学与理论推导

在工程实践中,它被广泛应用于:

  • 网络路由协议(如 RIP)
  • 含约束条件的最短路径问题
  • 金融中的套利检测
  • 编译器中的依赖分析

本项目将以教学 + 工程实现为目标,使用 C++,完整实现:

贝尔曼-福特算法,用于从给定节点出发,计算到有向图中所有其他节点的最短距离,其中边权为实值长度。

项目需求详细介绍

1. 图模型

  • 有向图(Directed Graph)
  • 节点编号:0 ~ N-1
  • 每条边包含:
    • 起点 u
    • 终点 v
    • 实值权重 wdouble,可为负)

2. 输入参数

  • 节点数量 N
  • 边集合 edges
  • 源点(起始节点)source

3. 输出要求

  • 返回从 source 到所有节点的最短距离
  • 若某节点不可达,返回 +∞
  • 若检测到负权环,应明确给出提示

4. 非功能性要求

  • 使用标准 C++(C++11 及以上)
  • 不依赖第三方图算法库
  • 代码结构清晰,包含详细中文注释
  • 适合教学、博客与工程复用

相关技术详细介绍

1. 最短路径的松弛(Relaxation)思想

贝尔曼-福特算法的核心思想是 松弛操作

对于一条边 (u → v, w)

if dist[u] + w < dist[v]: dist[v] = dist[u] + w 

该操作表示:

如果通过 u 再走一条边可以得到更短路径,就更新 v 的最短距离。

2. 为什么需要重复 N-1 次?

在一个没有负权环的图中:

  • 任意最短路径最多包含 N-1 条边

因此:

  • 只要对所有边重复进行 N-1 轮松弛
  • 就一定可以得到正确的最短路径结果

3. 负权环检测原理

如果在完成 N-1 轮松弛之后:

  • 仍然存在一条边可以被继续松弛

则说明:

图中存在 负权环,最短路径不存在(可无限减小)。

这是贝尔曼-福特算法相对于 Dijkstra 的一个关键优势。

4. 时间复杂度

  • 时间复杂度:O(N · E)
  • 空间复杂度:O(N)

虽然效率不如 Dijkstra,但在负权场景中不可替代。


实现思路详细介绍

整个实现可以严格分为以下几个步骤。

步骤一:定义边的数据结构

  • 每条边保存 (from, to, weight)

步骤二:初始化距离数组

  • 源点距离为 0
  • 其他节点距离初始化为 +∞

步骤三:执行 N-1 轮松弛

  • 每一轮遍历所有边
  • 对每条边尝试更新最短距离

步骤四:检测负权环

  • 再额外遍历一次所有边
  • 若还能松弛,则存在负权环

步骤五:输出结果

  • 给出每个节点的最短距离

完整实现代码

⚠️ 严格遵循你的记忆要求:所有代码放在单个代码块中,不拆分文件,不重复出现代码块
/**************************************************** * File: bellman_ford.cpp * Description: * 使用贝尔曼-福特算法计算有向图最短路径 * 支持实值边权与负权检测 ****************************************************/ #include <iostream> #include <vector> #include <limits> /**************************************************** * 边结构体 ****************************************************/ struct Edge { int from; // 起点 int to; // 终点 double weight; // 边权(实值) Edge(int u, int v, double w) : from(u), to(v), weight(w) {} }; /**************************************************** * 贝尔曼-福特算法 * @param n 节点数量 * @param edges 边集合 * @param source 源点 * @param dist 输出:最短距离数组 * @return 是否存在负权环(true 表示存在) ****************************************************/ bool bellmanFord( int n, const std::vector<Edge>& edges, int source, std::vector<double>& dist) { const double INF = std::numeric_limits<double>::infinity(); // 初始化距离 dist.assign(n, INF); dist[source] = 0.0; // 进行 N-1 轮松弛 for (int i = 0; i < n - 1; ++i) { bool updated = false; for (const auto& e : edges) { if (dist[e.from] < INF && dist[e.from] + e.weight < dist[e.to]) { dist[e.to] = dist[e.from] + e.weight; updated = true; } } // 若本轮无更新,可提前结束 if (!updated) { break; } } // 检测负权环 for (const auto& e : edges) { if (dist[e.from] < INF && dist[e.from] + e.weight < dist[e.to]) { return true; // 存在负权环 } } return false; // 不存在负权环 } /**************************************************** * 主函数:示例演示 ****************************************************/ int main() { // 节点数量 int n = 5; // 构造有向图的边集合 std::vector<Edge> edges = { Edge(0, 1, 6.0), Edge(0, 2, 7.0), Edge(1, 2, 8.0), Edge(1, 3, 5.0), Edge(1, 4, -4.0), Edge(2, 3, -3.0), Edge(2, 4, 9.0), Edge(3, 1, -2.0), Edge(4, 3, 7.0), Edge(4, 0, 2.0) }; int source = 0; std::vector<double> dist; bool hasNegativeCycle = bellmanFord(n, edges, source, dist); if (hasNegativeCycle) { std::cout << "Graph contains a negative-weight cycle." << std::endl; } else { std::cout << "Shortest distances from source " << source << ":" << std::endl; for (int i = 0; i < n; ++i) { if (dist[i] == std::numeric_limits<double>::infinity()) { std::cout << "Node " << i << ": unreachable" << std::endl; } else { std::cout << "Node " << i << ": " << dist[i] << std::endl; } } } return 0; } 

代码详细解读(仅解读方法作用)

Edge 结构体

用于表示有向图中的一条边,包含起点、终点以及实值权重。

bellmanFord 方法

该方法实现了贝尔曼-福特算法的完整流程:

  • 初始化最短距离数组
  • 执行 N-1 轮边松弛
  • 检测是否存在负权环
  • 返回计算结果与检测信息

main 方法

用于构造示例图、调用算法并输出最短路径结果。


项目详细总结

通过本项目,我们完整实现了:

  • 支持负权边的最短路径算法
  • 负权环的可靠检测机制
  • 一个清晰、稳定、可复用的 C++ 实现

贝尔曼-福特算法虽然在性能上不如 Dijkstra,但在:

  • 含负权问题
  • 教学与理论分析

中具有不可替代的地位。


项目常见问题及解答

Q1:为什么不能用 Dijkstra?

因为 Dijkstra 假设边权非负,在存在负权边时会得到错误结果。

Q2:算法能提前终止吗?

可以,如果某一轮松弛中没有任何更新,说明已收敛。

Q3:如何处理不可达节点?

距离保持为 +∞,表示从源点无法到达。


扩展方向与性能优化

  1. 输出具体最短路径(前驱数组)
  2. SPFA(队列优化的 Bellman-Ford)
  3. 与 Dijkstra 的性能与适用场景对比
  4. 在约束优化与差分约束系统中的应用
  5. 并行松弛策略的研究

如果你需要,我可以继续:扩展为输出完整路径而不仅是距离推导差分约束系统与 Bellman-Ford 的关系对比 SPFA 的优缺点写成图算法系列完整课程讲义

Read more

AppFlowy 终极安装配置完整教程:快速搭建个人AI知识库

AppFlowy 终极安装配置完整教程:快速搭建个人AI知识库 【免费下载链接】AppFlowyAppFlowy 是 Notion 的一个开源替代品。您完全掌控您的数据和定制化需求。该产品基于Flutter和Rust构建而成。 项目地址: https://gitcode.com/GitHub_Trending/ap/AppFlowy 还在为寻找完美的知识管理工具而烦恼吗?想要一个既强大又完全掌控数据的协作平台?AppFlowy作为Notion的开源替代品,为您提供AI协同工作空间,让项目管理、知识整理和团队协作变得前所未有的简单高效!🎯 📋 环境准备:搭建完美开发基础 在开始安装之前,请确保您的系统满足以下基本要求: 系统要求 * 操作系统:macOS 10.15+、Windows 10+ 或 Linux Ubuntu 18.04+ * 内存:建议8GB以上RAM * 存储空间:至少5GB可用空间 * 网络连接:稳定的互联网连接用于下载依赖 必备工具安装 首先需要安装Flutter和Rust开发环境: Flutter SDK安装:

By Ne0inhk

AI如何解决Cursor访问被阻止问题?

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 点击'项目生成'按钮,等待项目生成完整后预览效果 输入框内输入如下内容: 创建一个AI辅助工具,帮助开发者诊断和解决Cursor访问被阻止的问题。该工具应能自动检测系统权限设置、网络配置和可能的防火墙规则,提供详细的解决方案。支持多种操作系统(Windows、Mac、Linux),并能生成修复脚本或指导用户手动调整设置。工具应具备用户友好的界面,允许开发者输入错误信息并获取定制化的修复建议。 最近在开发过程中,遇到了一个让人头疼的问题——Cursor访问被阻止,提示cursor access blocked, please contact your admin。这个问题不仅影响了开发效率,还让我不得不花时间去排查各种可能性。幸运的是,通过AI辅助开发的工具,我找到了一个高效的解决方案。 1. 问题背景与常见原因 Cursor访问被阻止通常是由于系统权限、网络配置或防火墙规则引起的。具体来说,

By Ne0inhk
把 AI 学长“塞“进 QQ 群!我用 OpenClaw 为班级打造 24 小时智能助教

把 AI 学长“塞“进 QQ 群!我用 OpenClaw 为班级打造 24 小时智能助教

欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 把 AI 学长"塞"进 QQ 群!我用 OpenClaw 为班级打造 24 小时智能助教 * 前言:一个被 QQ 消息淹没的下午 * 什么是 OpenClaw? * 第一步:用 Lighthouse 应用模板一键部署 OpenClaw * 第二步:开放防火墙端口 * 第三步:配置 AI 模型与 QQ 通道 * 第四步:在 QQ 开放平台注册并实名认证 * 第五步:创建机器人「AI 学长」 * 第六步:获取 AppID

By Ne0inhk
AI详情页智能生成工作流 一键生成电商全品类主图丨海报丨详情页

AI详情页智能生成工作流 一键生成电商全品类主图丨海报丨详情页

借助AI工作流,电商设计进入自动化时代。无需复杂操作,只需上传产品图片,填写关键信息,系统即可智能生成高品质的电商视觉素材,覆盖主图、海报、详情页等多种场景。 🧭 使 1. 上传产品图片 将需要设计的产品图上传至系统。AI会自动识别产品轮廓,进行智能抠图与背景替换。 2. 填写提示信息 根据工作流内置的文本框提示,输入基础信息: * 产品颜色:如“红色、蓝色、黑色” * 卖点 1:如“轻盈防水材质” * 卖点 2:如“可折叠收纳,便捷携带” * 产品信息介绍:包含材质、尺寸、功能亮点、细节参数等 3. 点击生成 一键启动AI生成流程,系统自动完成主图、场景海报与详情页的版式设计与视觉渲染。 4. 等待出图即可 仅需数十秒,即可获得完整的电商详情页内容,可直接上传至平台使用。 🚀 功能亮点 * 全自动化:

By Ne0inhk