Bellman-Ford 算法 C++ 实现:负权图最短路径与负权环检测 5 步详解

发布时间:2026/7/12 1:13:44

Bellman-Ford 算法 C++ 实现:负权图最短路径与负权环检测 5 步详解
Bellman-Ford 算法 C 实现负权图最短路径与负权环检测 5 步详解1. 算法核心思想与适用场景Bellman-Ford 算法是图论中解决单源最短路径问题的经典算法由 Richard Bellman 和 Lester Ford 在 20 世纪 50 年代提出。与 Dijkstra 算法相比它的独特优势在于能够处理含有负权边的图同时具备检测负权环的能力。算法核心机制通过V-1 次松弛操作V 为顶点数逐步逼近最短路径每次迭代对所有边进行松弛更新源点到各顶点的最短距离最终通过额外迭代检测图中是否存在负权环典型应用场景网络路由协议如 RIP金融系统中的套利检测交通规划中的成本计算游戏开发中的路径寻找// 基础算法框架 for (int i 1; i V-1; i) { for (每条边(u,v)) { if (dist[u] w dist[v]) { dist[v] dist[u] w; } } }2. C 实现基础架构我们首先构建图的邻接表表示这是实现算法的数据结构基础#include vector #include climits struct Edge { int src, dest, weight; }; class Graph { private: int V; // 顶点数 std::vectorEdge edges; public: Graph(int vertices) : V(vertices) {} void addEdge(int u, int v, int w) { edges.push_back({u, v, w}); } bool bellmanFord(int src, std::vectorint dist) { // 初始化距离数组 dist.assign(V, INT_MAX); dist[src] 0; // 主松弛循环 for (int i 1; i V-1; i) { bool updated false; for (const auto edge : edges) { if (dist[edge.src] ! INT_MAX dist[edge.src] edge.weight dist[edge.dest]) { dist[edge.dest] dist[edge.src] edge.weight; updated true; } } if (!updated) break; // 提前终止优化 } // 负权环检测 for (const auto edge : edges) { if (dist[edge.src] ! INT_MAX dist[edge.src] edge.weight dist[edge.dest]) { return false; // 存在负权环 } } return true; } };3. 关键实现细节与优化3.1 松弛操作与提前终止Bellman-Ford 的核心在于松弛操作Relaxation其数学表示为dist[v] min(dist[v], dist[u] w(u,v))优化技巧提前终止当某次迭代没有发生任何距离更新时算法已收敛随机化处理顺序某些情况下可以加速收敛// 优化后的松弛循环 for (int i 1; i V-1; i) { bool updated false; for (const auto edge : edges) { if (relax(edge.src, edge.dest, edge.weight)) { updated true; } } if (!updated) break; // 提前终止 } bool relax(int u, int v, int w) { if (dist[u] ! INT_MAX dist[u] w dist[v]) { dist[v] dist[u] w; return true; } return false; }3.2 负权环检测机制负权环检测是算法的重要特性实现时需注意必须在完成 V-1 次迭代后执行只需检查是否能继续松弛无需实际遍历环检测逻辑对比表情况检测结果处理方式正常收敛无负权环返回正确距离仍可松弛存在负权环标记不可解4. 完整实现与测试用例下面是一个完整的实现包含路径重建功能#include iostream #include vector #include climits class BellmanFord { private: struct Edge { int src, dest, weight; }; int V; std::vectorEdge edges; public: BellmanFord(int vertices) : V(vertices) {} void addEdge(int u, int v, int w) { edges.push_back({u, v, w}); } bool solve(int src, std::vectorint dist, std::vectorint prev) { dist.assign(V, INT_MAX); prev.assign(V, -1); dist[src] 0; // 主算法循环 for (int i 1; i V-1; i) { bool updated false; for (const auto e : edges) { if (dist[e.src] ! INT_MAX dist[e.src] e.weight dist[e.dest]) { dist[e.dest] dist[e.src] e.weight; prev[e.dest] e.src; updated true; } } if (!updated) break; } // 负权环检测 for (const auto e : edges) { if (dist[e.src] ! INT_MAX dist[e.src] e.weight dist[e.dest]) { return false; } } return true; } void printPath(const std::vectorint prev, int v) { if (v 0) return; printPath(prev, prev[v]); std::cout v ; } }; // 测试用例 void testBellmanFord() { BellmanFord g(5); g.addEdge(0, 1, -1); g.addEdge(0, 2, 4); g.addEdge(1, 2, 3); g.addEdge(1, 3, 2); g.addEdge(1, 4, 2); g.addEdge(3, 1, 1); g.addEdge(3, 2, 5); g.addEdge(4, 3, -3); std::vectorint dist, prev; if (g.solve(0, dist, prev)) { for (int i 0; i 5; i) { std::cout Distance to i : dist[i] \tPath: ; g.printPath(prev, i); std::cout \n; } } else { std::cout Graph contains negative weight cycle!\n; } }5. 高级优化与工程实践5.1 SPFA 队列优化Shortest Path Faster Algorithm (SPFA) 是 Bellman-Ford 的队列优化版本bool spfa(int src, std::vectorint dist) { std::queueint q; std::vectorbool inQueue(V, false); std::vectorint count(V, 0); dist.assign(V, INT_MAX); dist[src] 0; q.push(src); inQueue[src] true; while (!q.empty()) { int u q.front(); q.pop(); inQueue[u] false; for (const auto e : edges) { if (e.src u dist[u] e.weight dist[e.dest]) { dist[e.dest] dist[u] e.weight; if (!inQueue[e.dest]) { q.push(e.dest); inQueue[e.dest] true; if (count[e.dest] V) { return false; // 负环检测 } } } } } return true; }5.2 实际工程注意事项数值溢出处理// 使用安全的加法防止溢出 if (dist[u] ! INT_MAX edge.weight 0 dist[u] INT_MAX - edge.weight) { // 处理溢出情况 }并行化可能性每轮迭代中的边处理可以并行执行需要原子操作保证距离更新的正确性内存访问优化// 按源点分组边可以提高缓存命中率 std::vectorstd::vectorEdge adj(V); for (const auto e : edges) { adj[e.src].push_back(e); }在实际项目中Bellman-Ford 算法常被用于网络路由协议和金融系统中的套利检测。我曾在一个高频交易系统中实现该算法来检测货币兑换环路的套利机会通过优化后的 SPFA 版本我们能够实时监控数十种货币对的汇率变化当发现负权环时立即触发交易策略。

相关新闻

NBM7100A与PIC18F4685在低功耗设备中的能量管理方案

NBM7100A与PIC18F4685在低功耗设备中的能量管理方案

2026/7/12 1:13:44

1. 项目背景与核心挑战在物联网和低功耗设备领域,如何最大化利用不可充电的初级电池(如锂锰电池)的能量一直是个棘手问题。这类电池在突发电流负载下表现尤为脆弱——电压骤降会导致设备意外重启,而电池内剩余的大量能量却无法被有…

GodotSteam游戏性能优化实战:10个技巧解决内存与网络瓶颈

GodotSteam游戏性能优化实战:10个技巧解决内存与网络瓶颈

2026/7/12 1:13:44

1. 项目概述:为什么GodotSteam项目需要性能优化?如果你正在用Godot引擎开发Steam平台的游戏,尤其是带有多人联机功能的项目,那么“性能”这个词,大概率已经让你头疼过不止一次了。我经历过不止一个项目,在开…

Node.js 核心模块实战:path 与 fs

Node.js 核心模块实战:path 与 fs

2026/7/12 1:13:44

从路径拼接到文件读写,掌握 Node.js 两大核心模块,并理解 JS 异步编程的完整进化链。📌 本文结构 path 模块(路径处理) → fs 模块(文件系统)→ 同步 vs 异步 → 异步进化史(回调 →…

遨博E5 ROS Melodic 仿真到真机:Gazebo PID报错解析与3步网络配置避坑

遨博E5 ROS Melodic 仿真到真机:Gazebo PID报错解析与3步网络配置避坑

2026/7/12 3:03:49

遨博E5 ROS Melodic仿真与真机联调实战:从Gazebo报错到网络配置全解析1. 仿真环境搭建与PID报错深度剖析在ROS Melodic环境下启动遨博E5机械臂Gazebo仿真时,开发者常会遇到PID控制器报错问题。这个看似简单的警告信息背后,其实反映了机器人控…

如何用HsMod插件全面优化炉石传说游戏体验:55项功能深度解析

如何用HsMod插件全面优化炉石传说游戏体验:55项功能深度解析

2026/7/12 3:03:49

如何用HsMod插件全面优化炉石传说游戏体验:55项功能深度解析 【免费下载链接】HsMod Hearthstone Modification Based on BepInEx 项目地址: https://gitcode.com/GitHub_Trending/hs/HsMod 炉石传说玩家们,你是否厌倦了漫长的等待动画&#xff1…

如何高效使用GBFR Logs:专业级碧蓝幻想Relink伤害监控终极指南

如何高效使用GBFR Logs:专业级碧蓝幻想Relink伤害监控终极指南

2026/7/12 3:03:49

如何高效使用GBFR Logs:专业级碧蓝幻想Relink伤害监控终极指南 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mirrors/gb/gbfr-logs …

libgdbm-rust项目贡献指南:如何参与开源项目开发与代码贡献

libgdbm-rust项目贡献指南:如何参与开源项目开发与代码贡献

2026/7/12 3:03:49

libgdbm-rust项目贡献指南:如何参与开源项目开发与代码贡献 【免费下载链接】libgdbm-rust rewrite gdbm tool by using Rust 项目地址: https://gitcode.com/openeuler/libgdbm-rust 前往项目官网免费下载:https://ar.openeuler.org/ar/ libgdb…

MoE模型prefill并行化:专家并行架构与vLLM优化实践

MoE模型prefill并行化:专家并行架构与vLLM优化实践

2026/7/12 3:03:49

在大模型推理优化领域,MoE模型的prefill阶段并行化是一个极具挑战性的技术难题。当每个token都需要动态选择专家时,如何实现prefill阶段的高效并行计算,直接关系到模型推理的吞吐量和响应延迟。本文将深入探讨MoE模型prefill并行的核心原理、…

Python中with open:不关文件?等着被OSError暴揍吧

Python中with open:不关文件?等着被OSError暴揍吧

2026/7/12 2:53:48

open() 函数内置函数使用来打开一个文件的open()函数, 会返回文件对象, 在对文件展开处理进程当中都得用到这个函数, 要是该文件没能成功被打开, 便会抛出。留意, 运用 open() 函数时, 务必要确保将文件对象关闭, 也就是要调用 close() 函数。open()函数, 其常用形式为, 接收两…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/12 0:03:42

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/12 0:03:42

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/12 0:03:42

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/12 0:03:42

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/12 0:03:42

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/12 0:03:42

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…