算法学习笔记(最短路——Dijkstra)

D i j k s t r a Dijkstra Dijkstra是最常用,效率最高的最短路径算法,是单源最短路算法。核心是 B F S BFS BFS和贪心。

B F S BFS BFS传送门

D i j k s t r a Dijkstra Dijkstra大概分成以下几个步骤:

  1. 从起点出发扩展它的邻点。
  2. 选择一个最近的邻点继续向外拓展它的邻点。(贪心的思想,保证了拓展完之后该点一定是最短路径,不用重复拓展。若从不是从距离最近的点向外拓展,可能存在一条路从起点经过最近点到达该点,就需要重复计算。)
  3. 重复步骤 2 2 2直到所有点都被拓展过了。

如何快速地取得步骤 2 2 2中描述的所谓最近邻点?可以使用优先队列来实现。就是说用优先队列来代替原来 B F S BFS BFS中的普通队列。

算法复杂度: O ( m l o g 2 n ) O(mlog_2n) O(mlog2n)。

算法缺点:边权不能为负数,若出现负边,则上述贪心思想失效(出现从另外一点经过一负边到达"最近点"的距离比原本到达"最近点"的距离短)。

存图:邻接表、前向星。


例题:【模板】最短路(2)- StarryCoding | 踏出编程第一步

题目描述

给定一个 n n n个点、 m m m条边的有向图,要求计算出点 1 1 1到点 n n n的最短距离。

可能存在重边和自环。

输入描述

第一行:两个整数 n , m n,m n,m。( 1 ≤ n , m ≤ 2 × 1 0 5 1 \le n,m \le 2 \times 10^5 1≤n,m≤2×105)

接下来 m m m行:每行三个整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi,表示存在一条从 u i u_i ui到 v i v_i vi,权值为 w i w_i wi的有向边。 ( 1 ≤ u i , v i ≤ n , 1 ≤ w i ≤ 1 0 6 ) (1 \le u_i, v_i \le n, 1 \le w_i \le 10^6) (1≤ui,vi≤n,1≤wi≤106)

可能存在重边和自环。

输出描述

一个整数,表示从 1 1 1到点 n n n的最短距离;若不存在从点 1 1 1到点 n n n的路径,则输出 − 1 −1 −1。

输入样例1

复制代码
3 3
1 2 5
2 3 2
1 3 10

输出样例1

复制代码
7

详细解释见代码注释

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 9;
const ll inf = 4e18;

int n, m;

struct Edge     //记录边
{
    int x; ll w;        //x:出点,w:边权
    bool operator < (const Edge &v) const   //重载运算符实现小根堆
    {
        return w > v.w;
    }
};

vector<Edge> g[N];      //邻接矩阵存图
int vis[N];     //记录第i点是否被拓展过
ll d[N];        //d[i]表示从起点到点i的最短路径长度

void dijkstra(int st)
{
    for(int i = 1; i <= n; ++i)     //初始化不要忘记
    {
        d[i] = inf;
    }
    d[st] = 0;

    //BFS
    priority_queue<Edge> q;
    q.push({st, d[st]});        //将起点存入优先队列

    while(q.size())
    {
        int x = q.top().x;
        q.pop();

        //已经拓展过的点不再拓展,因为已经求得了最短路
        if(vis[x])continue;
        vis[x] = 1;
        
        for(auto &[y, w] : g[x])
        {
            //若出点也没拓展过且可以拓展,加入待拓展队列
            if(!vis[y] && d[y] > d[x] + w)
            {
                d[y] = d[x] + w;
                q.push({y, d[y]});
            }
        }
    }
}

void solve()
{
    cin >> n >> m;
    for(int i = 1; i <= m; ++i)
    {
        int u, v, w; cin >> u >> v >> w;
        g[u].push_back({v, w});
    }

    dijkstra(1);

    cout << (d[n] == inf ? -1 : d[n]) << '\n';
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
    while(_--) solve();
    return 0;
}

易错提示:不要忘记初始化,不要忘记初始化,不要忘记初始化。

相关推荐
正在走向自律12 小时前
【3/5】人工智能训练师 三级/高级工 考证学习方向:从“独立执行”到“设计、归因与全链条负责”
人工智能·学习·人工智能训练师·注方案设计·数据质控负责人·模型评测与调优辅助·ai训练项目交付
蒸蒸yyyyzwd12 小时前
后端学习笔记三个知识
笔记·八股
nm_zfyjt13 小时前
信息流广告投放优化实践:线索成本评估模型与转化链路重构(家装建材案例)
算法·重构·内蒙古朋友圈广告服务商·内蒙古朋友圈获客
CCIE-Yasuo13 小时前
网络安全-学习数据库-Mysql-2
数据库·学习·mysql
La Pulga14 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
w_zero_one14 小时前
算法--构造
java·数据结构·算法
其实防守也摸鱼15 小时前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
Zhao-Jichao15 小时前
AI Prompting for Everyone 课程笔记 - P19 数据分析 Data Analysis
人工智能·笔记·数据分析
li星野15 小时前
【学习记录】逻辑分析仪完全入门:从品牌方案到采样率、存储深度的核心概念解析
学习
旖旎夜光15 小时前
【C++ 基础入门】类和对象(上):封装、对象模型与 this 指针
开发语言·c++·笔记·学习