Bellman-Ford算法

Bellman-Ford算法是一种用于解决单源最短路径问题的算法,它可以在加权图中找到从一个源点到所有其他顶点的最短路径,即使图中包含负权边。与Dijkstra算法不同,Bellman-Ford算法能够处理负权边,并且可以检测图中是否存在负权环

Bellman-Ford算法的基本思想

Bellman-Ford算法的核心思想是动态规划。它通过逐步松弛(relaxation)图中的所有边,逐步逼近最短路径的值。算法的基本步骤如下:

  1. 初始化

    • 将源点到自身的距离设为0,即 dist[source] = 0
    • 将源点到其他所有顶点的距离设为无穷大,即 dist[v] = +∞
  2. 松弛操作

    • 对图中的每条边 (u, v),尝试更新从源点到顶点 v 的距离:
      if dist[u] + weight(u, v) < dist[v]:
          dist[v] = dist[u] + weight(u, v)
      
    • 这个操作称为松弛,目的是找到更短的路径。
  3. 重复松弛操作

    • 对所有边重复上述松弛操作 n-1 次(其中 n 是图中顶点的数量)。根据最短路径的性质,任何最短路径最多包含 n-1 条边,因此经过 n-1 次松弛后,所有最短路径的值都会被正确计算。
  4. 检测负权环

    • 再次遍历所有边,如果还能找到可以松弛的边(即 dist[u] + weight(u, v) < dist[v]),则说明图中存在负权环,无法找到最短路径。

Bellman-Ford算法的实现

以下是Bellman-Ford算法的标准实现:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;

struct Edge {
    int u, v, weight; // 表示边 (u, v),权重为 weight
};

bool bellmanFord(int n, int source, vector<Edge>& edges, vector<int>& dist) {
    // 初始化距离数组
    dist.assign(n + 1, INT_MAX); // 假设顶点编号从1开始
    dist[source] = 0; // 源点到自身的距离为0

    // 进行 n-1 次松弛操作
    for (int i = 1; i < n; i++) {
        bool updated = false; // 用于检测是否还有更新
        for (const auto& e : edges) {
            if (dist[e.u] != INT_MAX && dist[e.u] + e.weight < dist[e.v]) {
                dist[e.v] = dist[e.u] + e.weight;
                updated = true;
            }
        }
        if (!updated) break; // 如果没有更新,提前终止
    }

    // 检测负权环
    for (const auto& e : edges) {
        if (dist[e.u] != INT_MAX && dist[e.u] + e.weight < dist[e.v]) {
            return false; // 存在负权环
        }
    }

    return true; // 不存在负权环
}

int main() {
    int n, m, source;
    cout << "Enter number of vertices and edges: ";
    cin >> n >> m;
    cout << "Enter source vertex: ";
    cin >> source;

    vector<Edge> edges;
    cout << "Enter edges (u, v, weight):" << endl;
    for (int i = 0; i < m; i++) {
        Edge e;
        cin >> e.u >> e.v >> e.weight;
        edges.push_back(e);
    }

    vector<int> dist;
    if (bellmanFord(n, source, edges, dist)) {
        cout << "Shortest distances from source vertex " << source << ":" << endl;
        for (int i = 1; i <= n; i++) {
            if (dist[i] == INT_MAX) {
                cout << "Vertex " << i << ": No path" << endl;
            } else {
                cout << "Vertex " << i << ": " << dist[i] << endl;
            }
        }
    } else {
        cout << "Graph contains a negative-weight cycle." << endl;
    }

    return 0;
}

算法复杂度

  • 时间复杂度O(V * E),其中 V 是顶点数,E 是边数。因为算法需要对所有边进行 V-1 次松弛操作。
  • 空间复杂度O(V),主要用来存储距离数组。

适用场景

Bellman-Ford算法适用于以下场景:

  1. 图中可能包含负权边。
  2. 需要检测图中是否存在负权环。
  3. 图的边数较少(相对于顶点数),因为算法的时间复杂度较高。

如果图中没有负权边,且边数较多,通常推荐使用Dijkstra算法,因为它的时间复杂度更低(O(E + V log V))。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值