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. 从青铜到王者,揭秘 Serverless 自动化函数最佳配置

    [福利活动]1分钟Serverless部署PHP商城实验班上线啦! 带你体验如何使用 Serverless 应用引擎 SAE 快速部署一个PHP商城,并体验 SAE 带来的弹性伸缩.应用监控等强大能力 ...

  2. 创新推出 | Serverless 调试大杀器:端云联调

    背景 说起当前最火一个技术, 不可避免地讨论到一个概念: Serverless.作为一种新型的应用架构,Serverless 让我们摆脱了维护基础设施的繁琐,只需要上传代码包或者镜像, 即可得到一个弹 ...

  3. springboot 参数通过 @RequestBody传递的写法

    controller中有时候参数是使用 @RequestBody传递的这种怎么写? 直接上代码 @RequestMapping("/test") public void getAc ...

  4. oracle表空间已满解决

    在日常的oralce使用中最长遇到的问题就是oralce的表空间满了,数据无法写入报错,这种情况下通常是磁盘没有足够的空间或者表空间的数据文件达到32G(linux最大限制单个文件不超过32G)无法继 ...

  5. C#对字符串进行加密解密

    首先上效果图 加解密接口 internal string ToEncrypt(string encryptKey, string str) { try { byte[] P_byte_key = // ...

  6. MySQL的SQL优化常用30种方法[转]

    MySQL的SQL优化常用30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用!=或< ...

  7. pycharm设置保存时自动格式化代码(Auto Reformat Code)

    原文:https://blog.csdn.net/qq_41906934/article/details/124631826 1.手动格式化代码 Code -> Reformat Code 格式 ...

  8. 小程序:Now you can provide attr `wx:key` for a `wx:for` to improve performance. 的解决方案

    在wx:for后面添加wx:key="key" 可消除警告 <view wx:for="{{thisWeekMovies}}" wx:for-index= ...

  9. Laravel - 使用ajax

    一,前台模板文件  index.blade.php <!DOCTYPE html> <meta name="_token" content="{{ cs ...

  10. .Net 使用 MongoDB

    1.安装nuget包 MongoDB.Driver 2.简单代码 using MongoDB.Bson; using MongoDB.Driver; using System.Buffers; usi ...