代码随想录算法训练营第61天| 图论 Bellman_ford算法优化:1.队列优化算法 、2.判断负权回路、3.单源有限最短路

Bellman_ford队列优化算法(SPFA):

Bellman_ford的队列优化算法,又叫SPFA算法,两者指的是同一个算法。在初始的Bellman_ford算法中,每次松弛都将所有的边松弛了一次(也就是每轮松弛的时候每条边都会被处理一次)。但其中不全是有效的松弛,因为有的节点并没有被计算过,只有针对计算过的节点进行的松弛才是有效的松弛。比如说,如果一个边的起点甚至还没有被计算过,即到达该起点的最短路径是INT_MAX,并没有被更新过,对这样起点的边进行处理是没有必要的。所以,实际上我们只需要对上一次松弛的时候更新过的节点进行松弛就好了(因为没有更新的节点说明已经找到了到达他的最短距离)。使用队列实现优化,将当前访问的节点加入队列,取出队头元素,对队头元素所代表的节点作为出发点所连接的边进行松弛。

卡码网:94.城市间货物运输 I

题目链接:94. 城市间货物运输 I

思路:利用队列对上一次更新过的节点进行松弛。关于list容器,是一个双向链表。

代码:

#include<iostream>
#include<vector>
#include<list>
#include<climits>
using namespace std;
#include<queue>

struct Edge{//邻接表
    int to;//终点
    int val;//权值
    Edge(int t, int w): to(t),val(w){}//构造函数和初始化
};

int main(){
    int n, m, p1, p2, val;
    cin >> n >> m;//点数和边数
    //邻接表里存储某个点  相连的边  以及这个边的终点以及权值
    vector<list<Edge>> grid(n+1);
    //记录队列中是否已经存在这个点
    vector<bool> isInQueue(n+1);
    
    for(int i=0; i<m; i++){
        cin >> p1 >> p2 >> val;
        //往每个节点的链表里面存放边
        grid[p1].push_back(Edge{p2, val});
    }
    
    vector<int> minDist(n+1,INT_MAX);
    minDist[1] = 0;
    
    int start = 1;
    int end = n;
    
    queue<int> que;
    que.push(start);
    
    while(!que.empty()){
        int node = que.front();
        que.pop();
        isInQueue[node]=false;//这个点已经出队了就标记false
        
        //遍历以这个点为起点的所有节点
        for(Edge edge : grid[node]){
            int from = node;
            int to = edge.to;
            int value = edge.val;
            
            if(minDist[to] > minDist[from] + value){
                minDist[to] = minDist[from] + value;
                if(isInQueue[to] == false){
                    que.push(to);
                    isInQueue[to] = true;
                }
            }
        }
    }
    if(minDist[end] == INT_MAX) cout << "unconnected";
    else cout << minDist[end];
    
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值