Dijkstra算法总结(C/C++) 您所在的位置:网站首页 dijkstra是什么 Dijkstra算法总结(C/C++)

Dijkstra算法总结(C/C++)

2022-11-06 14:40| 来源: 网络整理| 查看: 265

文章目录 一: Dijkstra算法分析二: 代码分析1. 一般代码 O(n * n)2. 优化代码 O(m * logn )

一: Dijkstra算法分析

 问题介绍: 在这里插入图片描述

 问题分析:   1.Dijkstra算法介绍   Dijkstra算法是基于贪心算法去求解的一个算法,它每次会选取一个离源点最近且还未被选取的点进行选取,总共进行n次选取最终可以选取到dis[n]的最短距离。   2.Dijkstra算法为什么只适用于边权为正值的问题?   解答:因为Dijkstra算法是每次选取到这个合法的点后会将此点的最短距离进行确定下来,它会默认这个点已经是最优解了,而可以进行这个默认的前提就必须是边权为正值,因为如果存在边权为负值则可能导致之后再次使用另一个点 y 去优化的过程将已经确定的点 x 的dis[x]的值可能再次减小,这就和这个算法的原理相违背了,不能确保每一次选取的点为最优点。   3.Dijkstra算法两种版本分析   a.传统版本:   找到未被选择的点当中离源点最近的点 x —— 确定这个点 x 的值dis[x] 已经被确立 —— 利用点 x 去循环遍历 x 和其他未被访问的点的距离。 重复这3个过程 n 次即可找到 n 个点到源点的最短路了。   因为我们是利用点与点之间的关系进行遍历的一共进行 n 次,每次需要遍历 n 个点 所以时间复杂度: O(n* n).   b.优化版本:   找到未被选择的点当中离源点最近的点 x —— 确定这个点 dis[x] 的值已经被确立 —— 这里我们可以做一个优化我们其实只需要去遍历和x有边相连接的点即可,因为如果没有边相连接我们其实遍历是多余的因为也是不可到达的。   总共遍历 n 次其实是一样的,核心在于我们更新与其他点的距离时利用的不再是点与点而是边之间的关系。 一共 m 条边,每次选取源点最近的点利用栈结构log n。时间复杂度O(m * log n)  算法总结:   1.单源最短路问题+边权为正值   2.两种版本时间复杂度:   传统Dijkstra算法:适用于稠密图. O (n n)   优化DIjkstra算法:适用于稀疏图. O(m logn)

二: 代码分析 1. 一般代码 O(n * n) #include using namespace std; //vis[]表示是否被选取了,dis[]表示离源点距离 ,g[][]存储点与点之间距离 const int N = 510, inf = 0x3f3f3f3f; bool vis[N]; int dis[N], g[N][N], n, m; int Dijkstra(){ //初始化源点为1 dis[1] = 0; //从未被选取的点当中选取到达源点最近的点 for(int i = 0; i if(!vis[j] && (t == -1 || dis[j] if(!vis[j] && dis[j] > dis[t] + g[t][j] ){ dis[j] = dis[t] + g[t][j]; } } } if(dis[n] == inf ) puts("-1"); else cout int x, y, s; cin >> x >> y >> s; //保存点与点之间的最短路径关系即可 g[x][y] = min(s, g[x][y] ); } Dijkstra(); } 2. 优化代码 O(m * logn ) #include #include #include #include #include using namespace std; typedef pair PII; const int N = 1.5e5 + 10; int n, m, dis[N]; bool vis[N]; int h[N], ne[N], w[N], e[N], idx; //链表存储边的关系 void add(int x,int y,int z){ w[++idx] = z, e[idx] = y, ne[idx] = h[x], h[x] = idx; } int dijkstra(){ //优先队列存储距离和点,按离源点距离排序,越小越在前面 //源点 x = 1, dis[1] = 0 priority_queue p_q; p_q.push({0, 1} ); dis[1] = 0; while(!p_q.empty() ){ auto t = p_q.top(); p_q.pop(); //****如果这个点已经被选取确定遍历过它的边,则跳过**** //否则选取这个点并设置为 true int d = t.first, u = t.second; if(vis[u]) continue; vis[u] = true; //利用u的边去更新和u有联系的点 for(int i = h[u]; ~i; i = ne[i] ){ int j = e[i]; if(dis[j] > d + w[i]){ dis[j] = d + w[i]; p_q.push({dis[j], j} ); } } } if(dis[n] == 0x3f3f3f3f ) return -1; return dis[n]; } int main(){ memset(h, -1, sizeof(h) ); memset(dis, 0x3f, sizeof(dis) ); cin >> n >> m; for(int i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有