Dijkstra算法求单源最短路

Dijkstra算法应用于求一个给定图的单个源点到其他各顶点的最短路。其中应用Dijkstra算法的图应满足如下条件

  • 图中没有负权边
  • 有向或者无向图都可以
  • 图中若有自环或者重边也可以(需要自己先筛选一下)

Dijkstra算法的核心就是从源点开始对各个顶点进行松弛操作,且每一次松弛选择出当前最优也就是离源点最小的路径(贪心),直到求出总体最小的路径。其贪心的正确性证明可以看这个AcWing 849. Dijkstra算法(含正确性证明) - AcWing

朴素的Dijkstra算法

所谓朴素的Dijkstra就是在寻找当前未收入最短路的最小顶点时采用最朴素的遍历操作来寻找,与后面采用堆来比较朴素。

实现Dijkstra的步骤如下

  1. 初始化dist数组为正无穷,且令dist[s] = 0;s代表源点,dist[k]表示k顶点到源点的距离。源点本身到自身距离为0,其他顶点尚未更新默认为正无穷。
  2. 遍历所有顶点,从未收入最短路(st[k] == false)且更新过(dist[k] != 0x3f3f3f3f)的顶点中找到到源点距离最小的点,即为v。
  3. 将v收入到最短路中(st[v] = true),使用v更新v的邻接点到源点的距离,当v的邻接点到源点的距离大于v到源点再到该点的距离时,更新。

实现代码如下

849. Dijkstra求最短路 I - AcWing题库

#include <iostream>
#include <cstring>
using namespace std;
const int N = 600;
int g[N][N],dist[N]; //g[N][N],图的存储,dist[N],各顶点到源点的距离
bool st[N]; //顶点是否已经收入最短路
int n; //顶点个数
void Dijkstra(int v)// v - > 源点
{
memset(dist, 0x3f, sizeof(dist));
dist[v] = 0;
for (int i = 0; i < n; i++) //一共n个顶点,最多做n次操作即可更新所有顶点
{
int tmp = -1;
for (int j = 1; j <= n; j++)
{
if (!st[j] && (tmp == -1 || dist[tmp] > dist[j]))
tmp = j;
} //从未收入且更新过的顶点中选取最小值。由于未更新的节点为正无穷,不用特别判断也会自动被覆盖
st[tmp] = true; //将上述顶点收入
for (int j = 1; j <= n; j++)
{
if (g[tmp][j] != -1 && !st[j])//若为tmp的邻接点且未加入最短路中
{
dist[j] = min(dist[j], dist[tmp] + g[tmp][j]);
}
}
}
} int main()
{
memset(g, -1, sizeof(g));
int m;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int x, y, z;
cin >> x >> y >> z;
g[x][y] = g[x][y] == -1 ? z : min(g[x][y], z);//若有重边,仅保留重边中较小的那条边
}
Dijkstra(1);
cout << (dist[n] == 0x3f3f3f3f ? -1 : dist[n]);
return 0;
}

几点细节

  1. 存储图的数组一般初始化为-1。
  2. 存储路径的数组初始化为无穷大,dist[源点] = 0;
  3. 若题目中说有重边,可以在建图时保留最小的一条边
堆优化的Dijkstra

可以看出朴素Dijkstra算法中寻找未收入的最小顶点这一步,每一次循环都要遍历一遍顶点,最坏要循环n次,也就是说这一步的时间复杂度为\(O(n^2)\)。

不妨重新审视这个操作。我们要求的只是寻找某个最小值的操作,因此可以使用小根堆这一数据结构来优化这个操作。对于n个顶点,求其最小值的时间复杂度为\(O(1)\),更新堆中的顶点的复杂度为\(O(logn)\),这样优化后的总时间复杂度为$$O(nlogn)$$

直接上代码

注意这里使用邻接表建图且STL实现的数据结构居多

850. Dijkstra求最短路 II - AcWing题库

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1e5 + 20;
typedef pair<int, int> PII; //使用pair来存储顶点,first是该顶点的dist,second是该顶点的编号
vector<PII> g[N];
int dist[N];
bool st[N];
int n, m;
void Dijkstra(int v)
{
memset(dist, -1, sizeof(dist));
dist[v] = 0;
priority_queue<PII, vector<PII>, greater<PII>>h;//建立小根堆的方法,优先队列默认大根堆
h.push({ 0,v }); //将源点加入堆中。first为dist的目的是让其作为第一关键字进行排序
while (!h.empty()) //结束条件为队列空,也就是所有顶点都出队了
{
auto tmp = h.top();//取出最小未收录的最小顶点
h.pop();
int seq = tmp.second, distance = tmp.first;
if (st[seq]) continue;//若该顶点已经加入最短路,说明上述tmp是一个冗余元素,直接丢掉进入下一轮操作
st[seq] = true; //标记为已经加入最短路
for (int j = 0; j < g[seq].size(); j++)
{
int q = g[seq][j].first, p = g[seq][j].second;
if (dist[q] > dist[seq] + p && !st[q]) // 若可以更新同时未加入最短路中
{
dist[q] = dist[seq] + p; //更新
h.push({ dist[q],q }); //加入更新队列中
}
} }
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int x, y, z;
cin >> x >> y >> z;
g[x].push_back({y,z}); //编号,边权
}
Dijkstra(1);
cout << (dist[n] == 0x3f3f3f3f ? -1 : dist[n]);
return 0;
}

Dijkstra实现单源最短路的更多相关文章

  1. Dijkstra算法——单源最短路算法

    一.介绍 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他各个节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 适用于有 ...

  2. 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)

    关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...

  3. [ACM_图论] Domino Effect (POJ1135 Dijkstra算法 SSSP 单源最短路算法 中等 模板)

    Description Did you know that you can use domino bones for other things besides playing Dominoes? Ta ...

  4. 【算法系列学习】Dijkstra单源最短路 [kuangbin带你飞]专题四 最短路练习 A - Til the Cows Come Home

    https://vjudge.net/contest/66569#problem/A http://blog.csdn.net/wangjian8006/article/details/7871889 ...

  5. 利用分支限界法求解单源最短路(Dijkstra)问题

    分支限界法定义:采用Best fist search算法,并使用剪枝函数的算法称为分支界限法. 分支限界法解释:按Best first的原则,有选择的在其child中进行扩展,从而舍弃不含有最优解的分 ...

  6. 【算法】单源最短路——Dijkstra

    对于固定起点的最短路算法,我们称之为单源最短路算法.单源最短路算法很多,最常见的就是dijkstra算法. dijkstra主要用的是一种贪心的思想,就是说如果i...s...t...j是最短路,那么 ...

  7. 单源最短路模板(dijkstra)

    单源最短路(dijkstra算法及堆优化) 弱化版题目链接 n^2 dijkstra模板 #include<iostream> #include<cstdio> #includ ...

  8. 牛客编程巅峰赛S1第6场 - 黄金&钻石&王者 C.星球游戏 (单源最短路,Dijkstra)

    题意:有\(n\)个点,\(m\)条双向边,两个方向的权值都是相等的,可以从\(A\)中的某个点出发走到\(B\)中的某个点,求所有路径中的最短距离,如果A和B中没有点联通,则输出\(-1\). 题解 ...

  9. 洛谷 P5837 [USACO19DEC]Milk Pumping G (单源最短路,dijkstra)

    题意:有一\(n\)个点,\(m\)条边的双向图,每条边都有花费和流量,求从\(1\)~\(n\)的路径中,求\(max\frac{min(f)}{\sum c}\). 题解:对于c,一定是单源最短路 ...

  10. 2018/1/28 每日一学 单源最短路的SPFA算法以及其他三大最短路算法比较总结

    刚刚AC的pj普及组第四题就是一种单源最短路. 我们知道当一个图存在负权边时像Dijkstra等算法便无法实现: 而Bellman-Ford算法的复杂度又过高O(V*E),SPFA算法便派上用场了. ...

随机推荐

  1. 【新手友好】用Pyspark和GraphX解析复杂网络数据

    从零开始 在本文中,我们将详细介绍如何在Python / pyspark环境中使用graphx进行图计算.GraphX是Spark提供的图计算API,它提供了一套强大的工具,用于处理和分析大规模的图数 ...

  2. vue路由模块化

    https://www.bilibili.com/video/BV1Tg411u7oy?from=search&seid=5098139115981575542&spm_id_from ...

  3. shell脚本(7)-shell运算

    文档目录: 一.算数运算符 二.关系运算符 三.布尔运算符 四.逻辑运算符 五.字符串运算符 六.文件测试运算符 算术运算符 下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20: ...

  4. 【VSCode】秒下vscode

    有时从vscode官网下载速度奇慢甚至失败,介绍一种方法可以秒下 进入官网选择要下载的版本 像我的电脑,下载网址根本打不开 修改下载网址,替换下载地址中红框字符串:vscode.cdn.azure.c ...

  5. SpringBoot - 阿里云OSS - 上传和删除

    1,首先在 pom.xml 中加入maven依赖 <!-- 阿里云oss --> <dependency> <groupId>com.aliyun.oss</ ...

  6. 媒体查询常用 - 移动端和PC端尺寸

    /* 移动端 */ @media all and (max-width: 768px) { } /* PC端 */ @media all and (min-width: 769px) { }

  7. bootstrap : 响应式导航

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  8. Go-错误-error

  9. 精通 VS 调试技巧,学习与工作效率翻倍!

    ​ 欢迎大家来到贝蒂大讲堂 ​ 养成好习惯,先赞后看哦~ ​ 所属专栏:C语言学习 ​ 贝蒂的主页:Betty's blog ​ 1. 什么是调试 当我们写代码时候常常会遇见输出结果不符合我们预期的情 ...

  10. [转帖]oracle通过pid查找执行SQL

    通过TOP 命令查看PID:1560 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1560 oracle 20 0 38.978g 0. ...