常见最短路问题

本文介绍了朴素Dijkstra算法及其在稠密图中的O(n^2)复杂度,以及堆优化后的Dijkstra算法在稀疏图中的O(mlogn)效率提升。还讨论了其他如Bellman-Ford、SPFA和Floyd算法在处理负权边和多源最短路问题时的应用。
摘要由CSDN通过智能技术生成

单源最短路:求一个点到其他所有点的最短距离

所有边权都是正数:

朴素Dijkstra算法:O(n^2) 稠密图(用邻接矩阵存)多用这种  (n是点,m是边)

朴素Dijkstra算法

        S:当前已确定最短距离的点

       ① 初始化距离:dist[1]=0,dist[i] = +无穷

       ②for i: 0~n

                t<----不在S中的,距离最近的点

                s<---t

                用t更新其它点的距离

 

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N =510;

int n,m;
int g[N][N];  //稠密图用邻接矩阵写
int dist[N];
bool st[N];

int dijkstra()
{
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;
    for(int i=0;i<n;i++)
    {
        int t =-1;
        for(int j=1;j<=n;j++)//遍历 dist 数组,找到没有确定最短路径的节点中距离源点最近的点t
            if(!st[j] && (t == -1 || dist[t]>dist[j]))
                t=j;
        st[t] = true;
        for(int j=1;j<=n;j++)//遍历 t 所有可以到达的节点 i
            dist[j] = min(dist[j], dist[t]+g[t][j]);
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL),cout.tie(NULL);
    cin>>n>>m;
    memset(g, 0x3f, sizeof g);  //初始化边无穷大
    while(m--)
    {   
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b] = min(g[a][b], c);  //a和b之间有多条边 只需要保留最短的
    }
    int t = dijkstra();
    
    cout<<t;
    
    return 0;
}

 堆优化版的Dijkstra算法:O(mlogn) 稀疏图(用邻接表存)多用这种

堆的两种实现方式:手写堆;优先队列

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 150010;
typedef pair <int ,int> PII;
int n,m;
int e[N] , ne[N], h[N], W[N], idx;
int dist[N];
bool st[N];

void add(int a, int b, int c)
{
    W[idx]  = c, e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({0,1});
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.second, distance = t.first;
        if(st[ver]) continue;
        st[ver] = true; 
        for(int i = h[ver];i!=-1;i = ne[i])
        {
            int j = e[i];
            if(dist[j]> W[i] + distance)
            {
                dist[j] = W[i] + distance;
                heap.push({dist[j], j});
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
    cin>>n>>m;
    memset(h, -1, sizeof h);
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    int t = dijkstra();
    cout<<t;
    return 0;
}

存在负权边:

Bellman-Ford: O(nm)

SPFA:   一般O(m),最坏O(nm)

多源汇最短路:起点终点不确定(源点就是起点;汇点就是终点)

Floyd算法: O(n^3)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值