Bellman-Ford算法C++实现

Bellman-Ford算法是一种用于解决带负权重边的单源最短路径问题的经典算法。该算法由理查德·贝尔曼和艾德加·福特于20世纪50年代提出。

以下是Bellman-Ford算法的详细介绍:

  1. 算法概述:

    • Bellman-Ford算法可以在图中存在负权重边的情况下,找到从起点到其他所有顶点的最短路径长度。
    • 该算法通过一系列松弛操作,逐步更新从起点到各个顶点的最短距离。
    • 该算法能够检测图中是否存在负权重回路,如果存在则算法会报错。
  2. 算法步骤:

    • 初始化:
      • 创建一个数组dist[]存储从起点到各个顶点的最短路径长度。初始时dist[s] = 0,dist[v] = ∞(对于v != s)。
      • 创建一个前驱数组prev[]记录每个顶点的前驱节点。初始时prev[v] = -1(表示还未确定前驱节点)。
    • 松弛过程:
      • 进行|V| - 1轮松弛操作,其中|V|为图中顶点的数量。
      • 在每一轮中,对图中的每条边(u, v)执行松弛操作:
        • 如果dist[v] > dist[u] + w(u, v),则更新dist[v] = dist[u] + w(u, v)并设置prev[v] = u
      • 这个过程保证了从起点到任意顶点的最短路径长度在|V| - 1轮内可以被找到。
    • 检测负权重回路:
      • 在完成上述|V| - 1轮松弛操作后,再进行一轮松弛操作。
      • 如果在这一轮中仍然有某条边(u, v)满足dist[v] > dist[u] + w(u, v),则说明图中存在一个负权重回路。
      • 此时算法终止,并返回一个标志,表示图中存在负权重回路。
  3. 算法复杂度:

    • Bellman-Ford算法的时间复杂度为O(|V| * |E|),其中|V|是顶点数,|E|是边数。
    • 这比Dijkstra算法的O(|E| log |V|)要慢,但可以处理负权重边。
  4. 算法应用:

    • Bellman-Ford算法广泛应用于路由协议、交通规划等领域,能够处理含有负权重边的图。
    • 该算法还可以用于检测图中是否存在负权重回路,这是Dijkstra算法无法做到的。
下面是一个详细的 C++ 实现,其中包括了算法的主体以及用于图的表示和算法测试的辅助代码。

Bellman-Ford 算法的 C++ 实现

#include <iostream>
#include <vector>
#include <limits>

using namespace std;

// 边的结构体,包含起点、终点和权重
struct Edge {
    int from, to, weight;
};

// 图的结构体,包含顶点数、边列表
struct Graph {
    int vertices;
    vector<Edge> edges;
    
    // 添加边
    void addEdge(int u, int v, int w) {
        edges.push_back({u, v, w});
    }
};

// Bellman-Ford 算法
bool bellmanFord(Graph& graph, int source, vector<int>& distances, vector<int>& predecessors) {
    int V = graph.vertices;
    int E = graph.edges.size();
    
    // 初始化距离表和前驱节点表
    distances.assign(V, numeric_limits<int>::max());
    predecessors.assign(V, -1);
    distances[source] = 0;

    // 松弛操作,对所有边重复 V-1 次
    for (int i = 1; i < V; ++i) {
        for (const auto& edge : graph.edges) {
            int u = edge.from;
            int v = edge.to;
            int weight = edge.weight;
            if (distances[u] != numeric_limits<int>::max() && distances[u] + weight < distances[v]) {
                distances[v] = distances[u] + weight;
                predecessors[v] = u;
            }
        }
    }

    // 检查负权回路
    for (const auto& edge : graph.edges) {
        int u = edge.from;
        int v = edge.to;
        int weight = edge.weight;
        if (distances[u] != numeric_limits<int>::max() && distances[u] + weight < distances[v]) {
            cout << "Graph contains a negative-weight cycle" << endl;
            return false; // 如果还能松弛,则说明图中存在负权回路
        }
    }

    return true;
}

int main() {
    Graph g;
    g.vertices = 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, 2, 5);
    g.addEdge(3, 1, 1);
    g.addEdge(4, 3, -3);

    vector<int> distances;
    vector<int> predecessors;

    if (bellmanFord(g, 0, distances, predecessors)) {
        cout << "Vertex   Distance from Source" << endl;
        for (int i = 0; i < g.vertices; ++i) {
            cout << i << "\t" << distances[i] << endl;
        }
    }

    return 0;
}

代码说明:

  1. 数据结构:使用 struct Edge 来表示图的边,struct Graph 来表示整个图。
  2. 图的初始化:通过 addEdge 函数向图中添加边。
  3. Bellman-Ford 算法实现
    • 初始化所有顶点的最短路径估计值为无穷大,除了源顶点为0。
    • 进行 V-1 次迭代来松弛所有边。
    • 最后,再检查一次所有边,以确定图中是否存在负权重循环。
  4. 输出:如果没有负权回路,输出从源顶点到所有其他顶点的最短距离。

这个实现是对 Bellman-Ford 算法的一个基本示例,适用于教学和理解算法流程。在实际应用中,可能需要根据具体情况进行调整和优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值