最短路算法Dijkstra(详细版)

最短路算法Dijkstra

ACM比赛最常用最短路算法
时间复杂度O(m*logn)
适用范围,单源最短路(求一个点到其他点的最短路),无负边。

算法的核心思想:不断选择当前最短路径的节点,并更新其他节点的最短路径距离。
题目链接https://www.luogu.com.cn/problem/P4779

#include <bits/stdc++.h>
#include <iostream>
#include<cstring>
#define LL long long 
#define x first
#define y second
using namespace std;
typedef pair<LL, LL> PII;
const int N=1e6,M=1e6;
int n,m,s;
LL dist[N];  // 存储最短路径距离的数组
bool  st[N]; // 标记数组,用于判断节点是否已经加入最短路径树
LL e[M], h[N], ne[M], w[M], idx; // 邻接表存储图的结构
void add(LL a, LL b, LL c){
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; 
    // 添加边(a, b)到邻接表中,边权为c
}
int main()
{
    cin>>n>>m>>s; // 输入节点数、边数和起始节点编号
    memset(h, -1, sizeof h); // 初始化邻接表
    memset(dist, 0x7f, sizeof dist); // 初始化距离数组,用0x7f表示无穷大
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c; // 输入边(a, b)的起点、终点和权值
        add(a,b,c); // 添加边(a, b)到邻接表中
    }
    priority_queue<PII, vector<PII>, greater<PII>> q; // 小根堆,用于选择最短路径的下一个节点
    dist[s] = 0; // 起始节点到自身的距离为0
    q.push({dist[s], s}); // 将起始节点加入小根堆
    while(!q.empty())
    {
        PII t = q.top(); // 获取当前最短路径的节点
        q.pop(); // 将节点从堆中移出
        if(st[t.y]) continue; // 如果节点已经在最短路径树中,则跳过
        else st[t.y] = true; // 将节点标记为已加入最短路径树
        for(int i = h[t.y]; ~i; i = ne[i]) // 遍历以节点t.y为起点的所有边
        {
            int j = e[i]; // 边的终点
            if(dist[j]>dist[t.y]+w[i]) // 如果经过节点t.y到达节点j的距离比当前最短路径更短
            {
                dist[j] = dist[t.y]+w[i]; // 更新节点j的最短路径距离
                q.push({dist[j], j}); // 将节点j加入小根堆
            }
        }
    }
    for(int i=1;i<=n;i++) cout<<dist[i]<<' '; // 输出每个节点到起始节点的最短路径距离
    return 0;
}

存图采用了链式前向星的存储方式:
e[i] 代表的是第i条边的终点。
ne[i] 代表的是第i条边的下一条边(下一条边和上一条边的起点是同一个节点)。
h[t] 代表的是节点为t的第一条边。
w[i] 代表第i条边的权重。

算法流程

  1. 创建一个距离数组dist[],用于记录起始节点到其他节点的最短路径距离。将起始节点的距离dist[s]初始化为0,其余节点的距离初始化为无穷大(或者一个较大的值)。
  2. 创建一个标记数组st[],用于标记节点是否已经加入最短路径树。将所有节点的标记st[]初始化为false。
  3. 使用优先队列(或最小堆)Q,将起始节点s加入Q,并将dist[s]设置为0。
  4. 当Q不为空时,重复以下步骤:
    4.1. 从Q中取出一个节点u,该节点是当前最短路径的候选节点。
    4.2. 如果节点u已经在最短路径树中(即st[u]为true),则跳过该节点。
    4.3. 将节点u标记为已加入最短路径树(st[u]设为true)。
    4.4. 遍历节点u的所有邻居节点v(即u能直接到达的节点):
    4.5. 如果通过节点u到达节点v的距离dist[v]比当前已知的最短路径更短,则更新dist[v]为dist[u]加上边(u, v)的权值,并将节点v加入Q。
  5. 循环结束后,dist[]中存储了起始节点到所有节点的最短路径距离。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真的卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值