dijkstra算法详解

Dijkstra算法图文详解 Dijkstra算法算是贪心思想实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离。 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。 这样一个有权图,Dijkstra算法可以计算任意节点到其他节点的最短 阅读详情

目录

  1. 前言
  2. 算法的属性
  3. 算法的原理和实现

前言

读完本文,可以尝试自己写代码做一下下面的两道题:

  1. Dijkstra 未优化版练习
  2. Dijkstra 优化版练习
    注意:第 1 1 1 道题可以使用 O ( N 2 ) O(N^2) O(N2) 的时间复杂度通过,第二道题则需要使用 O ( N log ⁡ N ) O(N \log N) O(NlogN) 的时间复杂度通过。其余方面二者没有任何区别。可以参考本文下面给出的两种 Dijkstra 算法的 C++ 模版,但建议自己写代码加深记忆。(理解为主,不要死记硬背算法,我之前吃过这方面的亏!!!)

一、算法属性

  1. Dijkstra 属于单元最短路算法,适用于计算以有向图中单一的一个点作为起点到图中任意一个点的距离。
  2. Dijkstra 算法的时间复杂度为 O ( N 2 ) O(N^2) O(N2) 或 O ( N log ⁡ N ) O(N \log N) O(NlogN) 级别,且不能处理负边权的情况。
  3. Dijkstra 适用于处理点少边多,即稠密图的最短路问题。

二、算法原理及实现

  1. 算法准备
    Dijkstra 也可以理解为一种 涂色法 。我们将一个图中的所有店分为两类:未确定的点和已确定的点,可以理解为红色点和白色点。为实现这个方案,我们需要开一个 bool 型的 vis 数组,用于存放我们的点的涂色情况, 0 0 0 表示白色点(即未确定), 1 1 1 表示已涂色红色点(即已确定)。为存储最短路,我们还需要一个 d d d 数组,存放的是从第 k k k 号点到任意一个点的距离。(程序中指定的 k k k 点作为起点)
  2. 算法实现
    (1)初始化: d k = 0 , d i = ∞ d_k=0, d_i=\infin dk​=0,di​=∞ 其中, i i i 在这个数组中的任意位置且 i ≠ k i \neq k i=k 。
    (2)核心部分
        我们可以使用一个 for 循环选出所有的白色点中的点中 d d d 值最小的点,记这个点的位置为 p ( p → 白色点 ) p (p \rightarrow \text{白色点}) p(p→白色点) 。接下来,我们开始枚举与这个点相邻的边,通过这个点的值更新边的另一个端点的值。具体来说,设我们枚举的这条边是有向边 p → w p \rightarrow w p→w ,则 d d d 数组的更新方式如下:
    d w ← min ⁡ { d w , d p + W p → w } d_w\leftarrow \min \{d_w, d_p+W_{p \rightarrow w}\} dw​←min{dw​,dp​+Wp→w​}
    在上面的算式中, W W W 数组表示每条边的边权。这个操作有一个更加书面化的表达:松弛。每松弛一次,周围点的 d d d 值也会相应的更新一次。
    (3)举例模拟
        为了更好地理解上面所述的文字内容,我将用下面的图片说明算法的实现。
    图1
    通过上面的操作,我们可以得知, d = { 0 , 3 , 2 , 2 } d=\{0, 3, 2, 2\} d={0,3,2,2} 。

(4)代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 2510;

struct Node
{
    int to, wi;
};

int n, m, x, y, vis[N], d[N];
vector<Node> g[N];

int main()
{
    cin >> n >> m >> x >> y;
    for (int i = 1, u, v, w; i <= m; ++i)
    {
        cin >> u >> v >> w;

        g[u].push_back( Node{v, w} );
        g[v].push_back( Node{u, w} );
    }

    memset(d, 0x3f, sizeof(d));
    d[x] = 0;

    for (int i = 1; i <= n - 1; ++i)
    {
        int minn = 1e9, p = 0;
        for (int j = 1; j <= n; ++j)
        {
            if (vis[j]) continue;
            if (d[j] < minn)
            {
                minn = d[j];
                p = j;
            }
        }

        vis[p] = 1;
        for (auto j : g[p])
        {
            if (vis[j.to]) continue;
            if (d[p] + j.wi < d[j.to])
            {
                d[j.to] = d[p] + j.wi;
            }
        }
    }

    cout << d[y] << endl;

    return 0;
}
  1. 考虑优化
    上面代码的时间复杂度为 O ( N 2 ) O(N^2) O(N2) ,不能解决 N ≤ 1 × 1 0 5 N \le 1 \times 10^5 N≤1×105 数据规模以上的问题。下面考虑优化,将其时间复杂度降为 O ( N log ⁡ N ) O(N \log N) O(NlogN) 。
    前置知识:优先队列(priority_queue)
    使用优先队列前,需要 #include <queue> 或 #include <bits/stdc++.h> 。
    优先队列相当于一个堆,有大根堆和小根堆。下面介绍优先队列的模版参数:
#include <bits/stdc++.h>
priority_queue< type, container, rule > q;
参数名作用取值示例
type指定 priority_queue 中存放的数据类型int, char 等
container指定 priority_queue 用来存放数组的结构常见的是 vector<type>
rule指定 priority_queue 用来比较大小的结构greater<type> 为小根堆,less<type> 为大根堆

下面是优先队列的一种不同于普通 queue 的常用操作。

方法作用
toppriority_queue 具有堆的性质的体现,返回 priority_queue 堆顶的值

注意:优先队列的 push,pop 和 top 操作的时间复杂度均为 O ( log ⁡ N ) O(\log N) O(logN)
我们可以开始的时候定义一个 typedef pair<int, int> pii ,然后将 priority_queue 里面存放成 first 项为最短路,second 项为编号的 pair 类型对象。我们每次取堆顶元素并删除(使用 pop 操作),然后遍历堆顶元素的对应边,更新时只需将另一个端点的最短路和编号插入 priority_queue 即可(使用 push 操作)。
具体代码如下:

#include <bits/stdc++.h>

using namespace std;

#define x first
#define y second

const int N = 2e5 + 10;

typedef pair<int, int> pii;

int n, m, d[N], v[N];
priority_queue< pii, vector<pii>, greater<pii> > q;
vector< pii > e[N];

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

    memset(d, 0x3f, sizeof(d));
    q.push( {0, 1} );
    d[1] = 0;

    while (!q.empty())
    {
        pii h = q.top();
        q.pop();

        if (v[h.y]) continue;
        v[h.y] = 1;

        for (pii t : e[h.y])
        {
            if (d[t.x] > h.x + t.y)
            {
                d[t.x] = h.x + t.y;
                q.push( {d[t.x], t.x} ); 
            }
        }
    }

    if (d[n] < 1e9) cout << d[n] << endl;
    else cout << -1 << endl;

    return 0;
}

附:本文中的输入格式
第一行包含整数 n , m n,m n,m ,表示点数和边数。
第二行至第 m + 1 m+1 m+1 行,每行三个整数 u , v , w u,v,w u,v,w ,表示每条边的起点、终点和边权。

Dijkstra算法图文详解和C++代码 文章目录1 Dijkstra算法基本原理2 算法过程图解1(有向图)3 算法过程图解2(无向图)4 C++代码4.1 案例1代码4.2 案例2邻接矩阵定义4.3 案例2代码Dijkstra算法 1 Dijkstra算法基本原理 Dijkstra算法是根据贪心算法实现的,首先找出当前点到所有能到达的点之间最短的距离,然后松弛一次继续循环。所谓松弛一次,就是在已经访问过的点中遍历一遍,看看有没有更... 阅读详情

相关推荐

算法详解——Dijkstra算法

Dijkstra算法的目的是寻找单起点最短路径,其策略是贪心加非负加权队列。

python_plus的博客 3726

Dijkstra 算法

是由荷兰计算机科学家 Edsger Wybe Dijkstra 在1956年发现的算法,戴克斯特拉算法使用类似广度优先搜索的方法解决。Dijkstra 算法原始版本仅适用于找到两个顶点之间的最短路径,后来更常见的变体固定了一个顶点作为源结点然后找到该顶点到图中所有其它结点的最短路径,产生一个最短路径树。该算法每次取出未访问结点中距离最小的,用该结点更新其他结点的距离。需要注意的是绝大多数的 Dijkstra 算法不能有效处理带有的图。设一个赋权有向图。其中的每条边的权值为一个非负的实数。

人无远虑,必有近忧 2461

最短路dijkstra算法详解:dijkstra(图解)(详

本人小白,如果有写的不恰当的地方,还请大家指出,共同进步学习。 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------

mengxiang000000 9万+

Dijkstra 算法的实际应用

Dijkstra 算法是一种用于寻找单源最短路径的算法。它可以在有向图或无向图中使用,并且可以处理带有负权边的图。 Dijkstra 算法的实际应用非常广泛,其中包括: 路径规划:例如,在地图应用中使用 Dijkstra 算法来规划行车路线,或者在公共交通系统中使用 Dijkstra 算法来规划乘车路线。 网络路由:Dijkstra 算法也可以用于在计算机网络中找到从一台计算机到另一台计算机的...

weixin_35750953的博客 1956

【C语言】算法学习·Dijkstra算法详解

Dijkstra算法详解

m0_64560763的博客 4521

如何在Android上使用OpenCV进行摄像头标定

如何在Android上使用OpenCV进行摄像头标定,我们这里使用官方一个例程,其实并不难,只是网上的资料少了而已。相机标定是计算机视觉工作的前提,为了确定相机矩阵和畸变参数。

花草的博客 3440

Bellman-Ford算法和Dijkstra算法分别适用的情况有何不同?

Bellman-Ford算法和Dijkstra算法分别适用的情况有何不同? Bellman-Ford 求单源最短路,可以判断有无负权回路(若有,则不存在最短路),时效性较好,时间复杂度O(VE)。Bellman-Ford算法是求解单源最短路径问题的一种算法。 单源点的最短路径问题是指: 给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。 bellman-ford...

qq469617582的博客 6262

Ubuntu16.04下禁用scp、sftp和winscp

在上一篇博文《Ubuntu16.04 搭建FTP服务器,设置用户权限为只许上传、禁止下载和删除》中,我讲述了Ubuntu16.04下配置FTP,并且设定用户权限为只能上传数据,禁止下载和删除数据。这算在FTP层面封堵了服务器数据泄露的途径。 但是,Ubuntu系统的scp和sftp还是起作用的,理论上只要能用本地机器ping通服务器,就可以用scp和sftp下载数据,这还是存在数据泄露可能的,所...

HPC&Geophysics攻城狮 5736

最基础的Dijkstra的应用

转自大神博客  点击打开链接Dijkstra算法1.定义概览Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。问题描述:在无向图 G=(...

ACM 6532

数字电路基础(CMOS电路、低功耗方法)

文章目录一、CMOS器件1.1.CMOS反相器1.2. CMOS与非门1.3.CMOS或非门1.4 CMOS与门和CMOS或门二、CMOS电路参数——功耗 一、CMOS器件 1.1.CMOS反相器 CMOS反相器实现非门功能,由一个PMOS管和一个NMOS管组成,其逻辑电路图如下: 其真值表如下: In PMOS NMOS Out 0 √ 导通 ×关闭 1 1 ×关闭 √...

Mr.翟的博客 1万+

缺陷检测:使用PatchCore训练自己的数据集

必须包含有训练图片(无缺陷图片)、测试图片(缺陷图片)和ground_truth,并且ground_truth必须与对应图片的名称相同。同上一篇结果一样,我的输出为原始图片大小,但是不知道是不是因为图片不是正方形的,导致训练结果不好。编写一个脚本,重新规划数据集的路径规则,但是我稍微写复杂了一点,使用了类来操作。第二种(复杂):编写一个自己的Dataset,参考。第一种(简单):将数据集路径规则改成项目中。返回的必须是一个字典类型,可以阅读。本人此次使用的是第一种方法。运行时,参数部分直接输入。

xiaoxTai的博客 6478

Dijkstra算法为什么不能用于负权图

Dijkstra算法是贪心算法,大概前提是,从当前的所有可能中就能找到全局的最优解,而负权图不满足这个条件(比如本文末尾的图例) 让我们从它的算法步骤上仔细分析一下:(如果需要算法详解点这里)     1.将图上的初始点看作一个集合S,其它点看作另一个集合     2.根据初始点,求出其它点到初始点的距离d[i] (若相邻, 则d[i]为边权值;若不相邻,则d[i]为无限大...

Kprogram的博客 2万+

用python自动复制粘贴excel表里某一列的数据到另一个表中

昨天接到人事小姐姐求助减轻复制粘贴的重复工作量,分享一下代码 半路新手上路 耶 把 2.xlsx 表里的第二列 的数据复制粘贴到 test.xlsx的第一列 python3.6.2 from openpyxl import Workbook from openpyxl import load_workbook from openpyxl.writer.excel import Exc...

weixin_33854644的博客 2万+

DijKstra算法C++详解

先放代码 /*迪杰斯特拉算法*/ #include<iostream> #include<iomanip> using namespace std; #define INFINITY INT_MAX #define MAX_VERTEX_NUM 20 #define TRUE 1 #define FALSE 0 #define OK 1 typedef struc...

weixin_43140251的博客 2109

【同等学力】01-逻辑符号表达

F(x): x是确诊者,G(x):x有症状F(x): x是老人,G(x):x是宠物,L(x,y): x喜欢y。

super_mochi1 1880

2024年12月数据月报

2024年12月大数据月报,为您准备了阿里、字节、百度等大厂150多篇实践案例

SmartSi 2654

Dijkstra算法详解

本文详细介绍了Dijkstra算法,使用方法,简单例子(有插图理解),附有例题

shsbsns的博客 2371

Python爬虫:抓取餐饮平台顾客评分与评价的完整教程

本文介绍了如何使用Python爬虫技术抓取餐饮平台上的餐厅评分和评论数据。我们通过三种主要的抓取方法:静态网页抓取(requests)、动态网页抓取(Selenium)和API抓取,展示了如何抓取餐饮平台的数据。还介绍了如何使用pandas对抓取的数据进行存储、清洗、分析,并进行可视化和情感分析。通过本文的学习,您应该能够掌握如何使用Python爬虫抓取餐饮平台的评论数据,并将这些数据应用于市场分析、顾客反馈和服务优化等领域。

2201_76125261的博客 1144
上一篇: 洛谷 P3612 [USACO17JAN] Secret Cow Code S 题解
下一篇: “24点”计算问题的算法分析和C++语言实现
Aobing_peterJr
博客等级 码龄2年 128粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值