*算法训练(leetcode)第五十一天 | Dijkstra(堆优化版)、Bellman_ford 算法

*47. 参加科学大会(第六期模拟笔试)-Dijkstra(堆优化版)

题目地址

这个版本的Dijkstra强度很大,很大一部分原因是对优先队列不熟悉。

优先队列的定义:

 priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pq;

其中,

  • pair<int, int>是指定优先队列的存储数据类型;
  • vector<pair<int, int>>是指定优先队列的底层容器类型;
  • mycomparison是用于定义优先队列排序规则的比较函数。

Dijkstra(堆优化版)讲解

时间复杂度: O ( E l o g E ) O(ElogE) O(ElogE)
空间复杂度: O ( V + E ) O(V + E) O(V+E)

// c++
#include<bits/stdc++.h>
using namespace std;
class mycmp{
public:
    bool operator()(const pair<int, int> & left, const pair<int, int> & right){
        return left.second > right.second;
    }    
};

bool cmp(const pair<int, int> & left, const pair<int, int> & right){
    return left.second > right.second;
}

struct Edge{
  int to;
  int val;
  
  Edge(int t, int v): to(t), val(v){}
};

int main(){
    int n, m;
    cin>>n>>m;
    
    vector<list<Edge>> edges(n+1);
    int left, right, val;
    for(int i=0; i<m; i++){
        cin>>left>>right>>val;
        edges[left].push_back(Edge(right, val));
    }
    int start = 1;
    int end = n;
    vector<int> minDist(n+1, INT_MAX);
    vector<bool> visited(n+1, false);
    //
    priority_queue<pair<int, int>, vector<pair<int, int>>, mycmp> pq;
    //
    pq.push({start, 0});
    minDist[start] = 0;
    
    while(!pq.empty()){
        pair<int, int> cur = pq.top();
        pq.pop();
        
        if(visited[cur.first]) continue;
        // 标记访问
        visited[cur.first] = true;
        // 更新节点到源点距离
        for(Edge edge : edges[cur.first]){
            if(!visited[edge.to] && edge.val + minDist[cur.first] < minDist[edge.to]){
                minDist[edge.to] = edge.val + minDist[cur.first];
                pq.push({edge.to, minDist[edge.to]});
            }
        }
    }
    if(minDist[end]!=INT_MAX) cout<<minDist[end];
    else cout<<-1;
    return 0;
}

*94. 城市间货物运输 I-Bellman_ford 算法

题目地址

Bellman_ford 算讲解

时间复杂度: O ( V ∗ E ) O(V * E) O(VE)
空间复杂度: O ( V ) O(V) O(V)

// c++
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m,left,right,val;
    cin>>n>>m;
    vector<vector<int>> edges;
    
    for(int i=0; i<m; i++){
        cin>>left>>right>>val;
        edges.push_back({left, right, val});
    }
    
    int start = 1;
    int end = n;
    
    vector<int> minDist(n+1, INT_MAX);
    minDist[start] = 0;
    // 对所有边松弛n-1次
    for(int i=1; i<n; i++){
        for(vector<int> &edge : edges){
            int from = edge[0];
            int to = edge[1];
            int val = edge[2];
            // 松弛操作
            if(minDist[from] != INT_MAX && minDist[to] > minDist[from]+val){
                minDist[to] =  minDist[from]+val;
            }
        }
    }
    if(minDist[end] == INT_MAX) cout<<"unconnected";
    else cout<<minDist[end];
    return 0;
}

总结

Dijkstra算法每次只更新与当前节点相连的结点的最小路径长度,BF算法每次更新所有结点的最小路径长度。

BF算法第k次计算的是距离源点有k条边的结点的最小路径长度。

Dijkstra只适用于无负权值的图,BF算法适用于有负权值无负回路的图。

BF在负回路图中会陷入死循环。若中间某次遍历各点的最短路径不再更新则遍历结束。

BF算法可用于检测是否有负回路:若n-1次遍历都结束后,若再进行一次遍历还能得到某些结点的更短路径,则存在负环路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值