C++ Bellman-Ford 算法2024 年 8 月 28 日 | 阅读 19 分钟 在本教程中,我们将学习 C++ 编程语言中 Bellman-Ford 算法的实现。 历史Bellman-Ford 算法是一种动态规划算法,用于在加权有向图中查找从单个源顶点到所有其他顶点的最短路径。当图可能包含负权重边,并且没有负权重循环时,它特别有用。 以下是 Bellman-Ford 算法的简要历史:
在图论和计算机科学的早期,就出现了寻找图中最短路径的问题。早期的算法,如 Dijkstra 算法 (1956),是为了在具有非负边权重的图中找到最短路径而开发的。
Bellman-Ford 算法由 Richard Bellman 和 Lester Ford 于 1958 年独立开发。美国数学家 Richard Bellman 因该算法的命名而受到赞誉。 Lester Ford 也是一位美国数学家,对算法的开发和分析做出了贡献。该算法由 Bellman 在《数学表格和其他计算辅助工具》杂志上发表的一篇题为“通过多个点的最短路径”的论文中发表。 Bellman-Ford 算法最初旨在解决在网格中寻找多个点之间最短路径的问题,该问题在运筹学和交通规划中都有应用。
Bellman-Ford 算法在开发后不久就被应用于解决图中的单源最短路径问题。人们认识到该算法可以处理具有正负边权重的图。 该算法的关键在于松弛原理,它迭代地改进到顶点的距离估计,直到它们收敛到最短路径。
计算机科学家和数学家随后的工作主要集中在优化 Bellman-Ford 算法和分析其复杂性。 1959 年,Edward F. Moore 发表了 Bellman-Ford 算法的一个变体,称为 Moore-Bellman-Ford 算法,在某些情况下效率更高。 该算法已在网络路由、计算机网络和交通系统等各个领域得到应用。
研究人员还研究了 Bellman-Ford 算法及其变体的计算复杂性。已知其时间复杂性为 O(V * E),其中 V 是图中的顶点数,E 是边数。 需要注意的是,Bellman-Ford 算法无法处理带有负权重循环的图,因为在这样的图中没有明确定义的最短路径。 Bellman-Ford 算法仍然是解决单源最短路径问题的基本且通用的工具,尤其是在处理可能包含负边权重的图时。它对计算机科学、运筹学和交通规划等各个领域都产生了重大影响。 应用
Bellman-Ford 算法用于计算机网络中,以查找数据包从一个节点传输到另一个节点的最短路径。当处理具有可变链路成本或可能存在负权重的网络时,它特别有用。
RIP(路由信息协议)等距离向量路由协议使用 Bellman-Ford 算法的变体来确定计算机网络中数据传输的最佳路由。
在网络设计中,Bellman-Ford 算法可以帮助确定网络组件的最佳位置,以最小化成本或延迟。
在交通和物流中,Bellman-Ford 算法可用于查找车辆到达目的地的最短路线,同时考虑道路状况和交通等因素。
电信网络通常涉及复杂的路由问题,其中 Bellman-Ford 算法可用于优化信号路由或最小化通信成本。
自动驾驶汽车和机器人通常使用 Bellman-Ford 等寻路算法来规划路线,同时避开障碍物并最大限度地缩短行驶时间。
在视频游戏开发中,Bellman-Ford 算法可用于寻路,允许非玩家角色 (NPC) 或游戏角色高效地导航游戏环境。
在制造业中,该算法可应用于优化机器或人员等资源向不同任务或生产流程的分配。
航空公司使用优化算法,包括 Bellman-Ford 算法的变体,来高效地调度航班和分配资源,同时考虑飞机可用性和机场限制等因素。
在项目管理中,该算法可以帮助确定项目网络中的关键路径,该路径表示必须在最短时间内完成以满足项目截止日期的任务序列。
GIS 应用程序使用 Bellman-Ford 算法执行各种任务,例如在地图上查找位置之间的最短路径、GPS 导航的路线规划以及分析空间数据。
城市规划者和交通管理系统使用该算法来优化交通流量、减少拥堵并改善交通基础设施。 C++ 中 Bellman-Ford 算法的实现输出 Enter the number of vertices and edges: 5 7 Enter the edges in the format (source, destination, weight): 0 1 2 0 2 4 1 2 -1 1 3 3 2 3 5 3 0 -2 4 3 1 Enter the source vertex: 0 Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 1 Vertex 3: -1 Vertex 4: 9223372036854775807 说明 1. 初始化 初始化一个距离向量或数组来存储从源顶点到所有其他顶点的暂定距离。将源顶点的距离设置为 0,将所有其他顶点的距离设置为无穷大。 2. 松弛 重复以下步骤 (V - 1) 次,其中 V 是图中的顶点数 对于图中的每条边,检查到源顶点的当前最短距离,如果找到更短的路径则更新它。新距离计算为到源顶点的距离与边权重的总和。如果这个新距离比之前已知的到目的顶点的距离短,则更新距离。 3. 负权重循环检测 执行 (V - 1) 次松弛步骤后,再次遍历所有边,检查是否存在仍然可以松弛的边(即是否存在更短的路径)。如果找到任何此类边,则表明图中存在负权重循环。 4. 最短路径结果 如果在步骤 3 中未检测到负权重循环,则距离向量将包含从源顶点到所有其他顶点的最短距离。您可以使用此信息来查找最短路径本身。 关键点
用例
示例示例 1:使用邻接表输出 Enter the number of vertices and edges: 5 8 Enter the edges in the format (source, destination, weight): 0 1 2 0 2 4 1 2 -1 1 3 3 2 3 5 3 0 -2 4 3 1 4 2 -3 Enter the source vertex: 0 Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 1 Vertex 3: -1 Vertex 4: 0 说明 在此示例中,我们使用图的邻接表表示来实现 Bellman-Ford 算法。以下是代码的详细说明:
我们包含必要的 C++ 库用于输入/输出 (iostream) 和数据结构 (vector)。 我们使用 namespace std; 以避免在标准库函数和对象前加上 std::。
我们定义了一个结构体 Edge 来表示图中的一条边。它包含三个字段:source(边的起始顶点)、destination(边的结束顶点)和 weight(与边相关的权重或成本)。
这是实现 Bellman-Ford 算法的主函数。 它接受三个参数: edges: Edge 结构体向量,表示图中的边。 V: 图中的顶点数。 source: 查找最短路径的源顶点。 在函数内部,我们初始化一个距离向量来存储从源顶点到所有其他顶点的暂定距离。最初,所有距离都设置为 INT_MAX,除了源顶点,它设置为 0。
该函数在循环中执行边的松弛,该循环运行 (V - 1) 次(其中 V 是顶点数)。此循环迭代地更新到顶点的距离。 它遍历所有边并检查是否存在通过源顶点到目的顶点的更短路径。如果找到更短的路径,则更新距离。
在松弛循环之后,代码通过再次遍历所有边来检查是否存在负权重循环。如果在 (V - 1) 次迭代后仍然找到更短的路径,则表明图中存在负权重循环。
如果未检测到负权重循环,则代码打印从源顶点到所有其他顶点的最短距离。
在主函数中,系统提示用户输入顶点数、边数和边详细信息。然后,调用 bellmanFord 函数执行最短路径计算。 示例 2:使用邻接矩阵输出 Enter the number of vertices and edges: 4 6 Enter the edges in the format (source, destination, weight): 0 1 2 0 2 4 1 2 -1 1 3 3 2 3 5 3 0 -2 Enter the source vertex: 0 Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 1 Vertex 3: -1 说明
此函数实现 Bellman-Ford 算法。 它接受三个参数: graph: 表示图的加权邻接矩阵的二维向量。graph[u][v] 表示从顶点 u 到顶点 v 的边的权重。 V: 图中的顶点数。 source: 查找最短路径的源顶点。
在函数内部,初始化一个距离向量来存储从源顶点到所有其他顶点的暂定距离。所有距离最初都设置为 INT_MAX,除了到源顶点的距离,它设置为 0。
该函数使用嵌套循环结构执行边的松弛。 它使用两个 for 循环遍历所有顶点对 (u, v),其中 u 是源顶点,v 是目的顶点。 对于每个顶点对 (u, v),它检查是否存在从顶点 u 到顶点 v 的更短路径。这是通过比较到 v 的当前距离 (distance[v]) 与到 u 的距离 (distance[u]) 和从 u 到 v 的边的权重 (graph[u][v]) 之和来确定的。 如果找到更短的路径,则 distance[v] 将更新为更短的距离。
松弛循环完成后,代码打印从源顶点到所有其他顶点的最短距离。 它显示了从源顶点到图中每个顶点的最短距离。
主函数遵循与示例 1 相似的结构,但输入格式不同。 用户不输入边,而是输入加权邻接矩阵作为二维向量 (graph)。每个条目 graph[u][v] 表示从顶点 u 到顶点 v 的边的权重。 示例 2 展示了当图使用邻接矩阵表示时,如何应用 Bellman-Ford 算法来查找加权图中的最短路径。当图是密集的并且您想使用简单的矩阵结构时,此表示很方便。 示例 3:自定义图表示在此示例中,我们将使用自定义结构来表示顶点和边。此示例提供了实现 Bellman-Ford 算法的不同视角。 编码 输出 Enter the number of vertices and edges: 4 6 Enter the edges in the format (source, destination, weight): 0 1 2 0 2 4 1 2 -1 1 3 3 2 3 5 3 0 -2 Enter the source vertex: 0 Shortest distances from source vertex 0: Vertex 0: 0 Vertex 1: 2 Vertex 2: 1 Vertex 3: -1 说明
代码首先包含必要的 C++ 库,用于输入/输出 (iostream) 和使用向量 (vector)。 using namespace std; 语句用于避免在标准库函数和对象前加上 std::。
定义了一个名为 Edge 的结构体来表示图中的一条边。 Edge 结构体有三个字段: source: 边的源顶点。 destination: 边的目的顶点。 weight: 边的权重或成本。
定义了另一个名为 Graph 的结构体来表示图。 Graph 结构体有三个字段: V: 图中的顶点数。 E: 图中边的数量。 edges: 存储表示图的边的 Edge 对象的向量。 Graph 结构体还包含一个构造函数,用于初始化顶点数 (V) 和边数 (E)。
在 Graph 结构体中,有一个 addEdge 函数。 此函数允许您通过指定源顶点、目的顶点和边权重方便地向图中添加边。 它将新边附加到 edges 向量。
bellmanFord 函数是 Bellman-Ford 算法的主要实现。 它接受两个参数:一个 Graph 对象 (graph) 和查找最短路径的源顶点。 该函数首先初始化一个名为 distance 的向量来存储从源顶点到所有其他顶点的暂定距离。最初,所有距离都设置为 INT_MAX(无穷大),除了到源顶点的距离,它设置为 0。
该函数使用嵌套循环结构来执行边的松弛。 外循环运行 (V - 1) 次迭代,其中 V 是图中的顶点数。 内循环遍历 edges 向量中的所有边,并检查是否存在通过当前权重为 w 的边从源顶点 (u) 到目的顶点 (v) 的更短路径。 如果找到更短的路径,则更新目的顶点的距离。
松弛循环完成后,代码打印从源顶点到所有其他顶点的最短距离。 它显示了从源顶点到图中每个顶点的最短距离。
主函数是程序的入口点。 它首先提示用户输入图中顶点数和边数。 它创建一个具有指定顶点数和边数的 Graph 对象 graph。 然后,系统提示用户使用循环输入格式为(源、目的、权重)的边。 最后,要求用户输入查找最短路径的源顶点,并以 graph 和 source 作为参数调用 bellmanFord 函数。 优点Bellman-Ford 算法具有多项优点,使其成为解决某些类型最短路径问题的宝贵工具:
缺点虽然 Bellman-Ford 算法有其优点,但它也存在某些缺点和局限性,这可能使其不适用于某些场景:
结论Bellman-Ford 算法是图论和网络路由中的一个基本算法。它用于查找从单个源顶点到加权有向图中所有其他顶点的最短路径,即使图中包含负边权重。关于 Bellman-Ford 算法需要记住的关键点包括:
图表示(邻接表或邻接矩阵)和数据结构的选择可能因具体的实现要求而异。Bellman-Ford 是解决各种最短路径问题的宝贵工具。 下一个主题C++ 中的冒泡排序算法 |
我们请求您订阅我们的新闻通讯以获取最新更新。