HOME

Bellman-Ford算法代码实现示例

简介

Bellman-Ford算法是一种用于计算加权图中单源最短路径的经典算法。与Dijkstra算法不同的是,Bellman-Ford算法能够处理包含负权重边的情况,并且可以检测到负权重循环的存在。下面我们将通过Python实现该算法。

算法原理

单源最短路径

给定一个加权图G=(V, E)和一个起始节点s,Bellman-Ford算法的目标是找到从s到图中每个顶点的最短路径。

松弛操作

在算法中,我们使用一个松弛操作来更新每一对边(u, v),其中u和v为图中的两个相邻顶点。松弛操作的目的是检查是否有更好的方式到达顶点v,并且如果找到一种更优的方式,则将这个新值记录下来。 [ \text{if } d[v] > d[u] + w(u, v) ] [ \text{then set } d[v] = d[u] + w(u, v) ]

负权重循环检测

Bellman-Ford算法的一个重要特性是它可以用来检测图中是否存在负权重循环。在执行了|V|-1轮松弛操作后,再进行一轮额外的松弛操作若还能找到更短路径,则说明存在一个负权重循环。

Python代码实现

import sys

class Graph:
    def __init__(self, vertices):
        self.V = vertices  # Number of vertices in the graph
        self.graph = []

    def add_edge(self, u, v, w):
        self.graph.append([u, v, w])

    def bellman_ford(self, src):

        # Step 1: Initialize distances from src to all other vertices as INFINITE
        dist = [float("Inf")] * self.V
        dist[src] = 0

        # Step 2: Relax all edges |V| - 1 times. A simple shortest path has at most |V| - 1 edges
        for _ in range(self.V - 1):
            for u, v, w in self.graph:
                if dist[u] != float("Inf") and dist[u] + w < dist[v]:
                    dist[v] = dist[u] + w

        # Step 3: check for negative-weight cycles. The above step guarantees shortest distances
        # if there is no negative weight cycle. If we get a shorter path, then there is a cycle.
        for u, v, w in self.graph:
            if dist[u] != float("Inf") and dist[u] + w < dist[v]:
                print(f"Graph contains negative weight cycle")
                return

        # Print the result
        self.print_solution(dist)

    def print_solution(self, dist):
        print("Vertex   Distance from Source")
        for node in range(self.V):
            print(f"{node}\t\t{dist[node]}")

# Example usage:
g = Graph(5)
g.add_edge(0, 1, -1)
g.add_edge(0, 2, 4)
g.add_edge(1, 3, 3)
g.add_edge(1, 2, 2)
g.add_edge(2, 3, 5)
g.add_edge(2, 4, 1)
g.add_edge(3, 4, -2)

source = 0
g.bellman_ford(source)

结果分析

在这个示例中,我们构建了一个包含5个顶点的图,并添加了相应的边和权重。源节点设为0号节点。通过调用bellman_ford方法并传入源节点作为参数,可以计算出从源节点到其他所有节点的最短路径。

总结

Bellman-Ford算法提供了一种处理加权图中单源最短路径问题的有效解决方案,并且能够检测负权重循环。尽管在没有负权重循环的情况下Dijkstra算法可能更为高效,但在实际应用中,尤其是需要处理包含负权重的情况时,Bellman-Ford算法仍然是一个重要的选择。

通过上述示例代码,我们可以清晰地看到如何实现这一算法并应用于具体的图结构中。