最短路

最短路

Reference:最短路

注意,下面的所有算法的图的存储方式都是使用了vector的方式,如果对存储方式有问题,请看我的另一篇博客:图的存储

Bellman-Ford

  • 基于 松弛(relax) 操作。

设起始节点为 S S S
定义 d i s t ( u ) dist(u) dist(u) S S S到当前节点 u u u的最短路径长度。
松弛操作 r e l a x ( u , v ) relax(u,v) relax(u,v)是指: d i s t ( v ) = m i n { d i s t ( v ) , d i s t ( u ) + e d g e _ l e n ( u , v ) } dist(v) = min\{dist(v), dist(u) + edge\_len(u,v)\} dist(v)=min{ dist(v),dist(u)+edge_len(u,v)}
因此有三角不等式: d i s t ( v ) ≤ d i s t ( u ) + e d g e _ l e n ( u , v ) dist(v) \le dist(u) + edge\_len(u,v) dist(v)dist(u)+edge_len(u,v)

  • 支持负权。

  • 能找到某个节点出发到所有节点的最短路,或者报告某些最短路不存在。

  • SPFA是Bellman-Ford的一种优化。

  • 算法核心:对所有的边进行松弛操作,直到不能进行松弛操作为止.

  • 终止条件:由于一次 松弛 会让最短路的边数至少+1,而最短路边数最多为 V − 1 V-1 V1 , V V V 是图中节点的个数。因此,至多执行 V − 1 V-1 V1 次松弛操作

代码实现:

void bellman_ford(){
    vector<int> dis(vertex_size, INF);
    int S = 2;
    dis[S] = 0;
    cout << "(bellman_ford)\nS = " << S << ":\t";

    for (auto elem : T[S]){
        dis[elem.first] = elem.second;
    }

    for (int i = 0; i < vertex_size - 1; i ++){ // 进行V-1次松弛操作,因为最短路至多有V-1条边
        bool flag = false; // 如果某一次没有进行松弛操作了,那么可以结束。
        for (int u = 0; u < vertex_size; u ++){
            for (auto elem : T[u]){
                if (dis[elem.first] > dis[u] + elem.second){
                    dis[elem.first] = dis[u] + elem.second;
                    flag = true;
                }
            }
        }
        if (!flag){
            //cout << "OVER" << endl;
            break;
        }
    }

    for (auto i : dis){
        cout << i << " ";
    }
    cout << endl;
}
  • 复杂度分析:
    • 时间复杂度: O ( V ⋅ E ) O(V{\cdot}E) O(VE),V是顶点数,E是边数。
    • 空间复杂度: O ( 1 ) O(1) O(1),除了必要的存储空间(比如,最短路数组dis和图的存储T).

例题:判断一个图中是是否有负环。
解答:先对所有边进行V-1次松弛操作(执行bellman_ford),然后,对所有边进行一次松弛操作,如果在这次松弛中,松弛成功了,那么一定存在负环。否者,不存在。

SPFA

  • 是bellman-ford的优化算法。
  • 在bellman-ford算法中,有时候我们不需要那么多的无用 松弛
  • 只有上一次被松弛的节点v,v所连接的边才可能引起下一次的松弛操作。
  • 用队列来维护“哪些结点可能会引
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值