首页 > 编程语言 >Dijkstra算法求最短路

Dijkstra算法求最短路

时间:2023-04-16 14:13:00浏览次数:45  
标签:dist idx int 短路 源点 Dijkstra 算法 ver 节点

一 、Dijkstra 只适用于单源最短路中所有边权都是正数的情况

二 、存储方式

    1、稠密图用邻接矩阵

    2、稀疏图用邻接表

三 、算法实现

  • 用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。将dist数组赋值为正无穷,dist[1]=0

  • 用一个状态数组 st 记录是否找到了源点到该节点的最短距离,state[i] 如果为真,则表示找到了源点到节点 i 的最短距离,state[i] 如果为假,则表示源点到节点 i 的最短距离还没有找到。

  • 遍历 dist 数组,找到一个节点 : 没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state[i] 赋值1

      

  • 遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i->j 的距离 更新 dist[j] = min(dist[j] , dist[i] + w[i][j])

      

 

  • 重复以上步骤一直到个点的state状态为真    

code:

1 : 邻接表实现

 1 #include<iostream>
 2 #define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
 3 using namespace std;
 4 const int N = 101010;
 5 
 6 int e[N], ne[N], h[N], w[N], idx;//邻接表
 7 
 8 int dist[N], st[N];        //dist[i] 1号点到i号点的最短距离  st[i] i号点的最短路距离是否确定
 9 
10 int n, m, x, y, z;
11 
12 void add(int a, int b,int c) {
13     e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
14 }
15 void Dijkstra() {
16     memset(dist, 0x3f, sizeof dist);
17     dist[1] = 0;
18     for (int i = 1; i <= n; i++)
19     {
20         int t = -1;
21 
22         for (int j = 1; j <= n; j++)
23             if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
24 
25         for (int k = h[t]; k != -1; k = ne[k])
26         {
27             int i = e[k];
28             if (dist[i] > dist[t] + w[k]) dist[i] = dist[t] + w[k];
29         }
30     }
31 }
32 int main()
33 {
34     fast;
35     memset(h, -1, sizeof h);
36 
37     cin >> n >> m;
38 
39     while (m--) {
40     
41         cin >> x >> y >> z;
42 
43         add(x, y, z);
44 
45     }
46 
47     Dijkstra();
48 
49     cout << dist[n];
50 
51     return 0;
52 }

 

2 : 邻接矩阵实现

 1 #include<iostream>
 2 #include<cstring>
 3 #define fast ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
 4 #define itn int
 5 using namespace std;
 6 
 7 const int N = 510;
 8 
 9 int n, m;
10 int map[N][N];
11 bool st[10010];
12 int dist[N];
13 
14 int dijkstra() {
15     memset(dist, 0x3f, sizeof dist);
16     dist[1] = 0;
17 
18     for (int i = 1; i <= n; i++)
19     {
20         int t = -1;
21 
22         for (int j = 1; j <= n; j++)
23             if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
24 
25         st[t] = true;
26 
27         for (int k = 1; k <= n; k++)
28             dist[k] = min(dist[k], dist[t] + map[t][k]);
29 
30     }
31     if (dist[n] == 0x3f3f3f3f) return-1;
32     return dist[n];
33 }
34 
35 int main() {
36     fast;
37 
38     cin >> n >> m;
39 
40     memset(map, 0x3f, sizeof map);
41 
42     for (int j = 1; j <= m; j++)
43     {
44         int a, b, c;
45         cin >> a >> b >> c;
46         map[a][b] = min(map[a][b], c);
47     }
48 
49     int t = dijkstra();
50 
51     cout << t;
52 
53     return 0;
54 }

dikstra算法时间复杂度为O(n^2) 主要耗时的步骤是从dist 数组中选出没有确定最短路径的节点中距离源点最近的点 t。

如果能在一组数中每次能很快的找到最小值,那么时间复杂度可以大大降低,这时候我们就能想到一种数据结构:优先队列

堆里存储距离和节点编号 pair<int,int>

优先队列定义 : priority_queue<Type, Container, Functional> 

Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶

 1 #include <cstring>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <queue>//堆的头文件
 5 
 6 using namespace std;
 7 
 8 typedef pair<int, int> PII;//堆里存储距离和节点编号
 9 
10 const int N = 1e6 + 10;
11 
12 int n, m;//节点数量和边数
13 int h[N], w[N], e[N], ne[N], idx;//邻接表存储图
14 int dist[N];//存储距离
15 bool st[N];//存储状态
16 
17 void add(int a, int b, int c)
18 {
19     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
20 }
21 
22 int dijkstra()
23 {
24     memset(dist, 0x3f, sizeof dist);//距离初始化为无穷大
25     dist[1] = 0;
26     priority_queue<PII, vector<PII>, greater<PII>> heap;//小根堆
27     heap.push({0, 1});//插入距离和节点编号
28 
29     while (heap.size())
30     {
31         auto t = heap.top();//取距离源点最近的点
32         heap.pop();
33 
34         int ver = t.second, distance = t.first;//ver:节点编号,distance:源点距离ver 的距离
35 
36         if (st[ver]) continue;//如果距离已经确定,则跳过该点
37         st[ver] = true;
38 
39         for (int i = h[ver]; i != -1; i = ne[i])//更新ver所指向的节点距离
40         {
41             int j = e[i];
42             if (dist[j] > dist[ver] + w[i])
43             {
44                 dist[j] = dist[ver] + w[i];
45                 heap.push({dist[j], j});//距离变小,则入堆
46             }
47         }
48     }
49 
50     if (dist[n] == 0x3f3f3f3f) return -1;
51     return dist[n];
52 }
53 
54 int main()
55 {
56     scanf("%d%d", &n, &m);
57 
58     memset(h, -1, sizeof h);
59     while (m -- )
60     {
61         int a, b, c;
62         scanf("%d%d%d", &a, &b, &c);
63         add(a, b, c);
64     }
65 
66     cout << dijkstra() << endl;
67 
68     return 0;
69 }

总结:

Dijkstra算法适用于求正权有向图中,源点到其余各个节点的最短路径。注意:图中可以有环,但不能有负权边 

 

 

 

标签:dist,idx,int,短路,源点,Dijkstra,算法,ver,节点
From: https://www.cnblogs.com/carrotbinbin1F/p/17323162.html

相关文章

  • 排序算法-归并排序
    归并排序MergeSort1.MergeSort介绍MergeSort是利用归并的思想实现的排序算法,该算法采用经典的分治策略(divide-and-conquer),是一种稳定的排序算法。分治法是将问题分(divide)为一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各个答案“修补”在一起,即分而治之......
  • 算法-二叉树的构造
    namespaceBinary;publicclassBinaryTree{publicNode<char>Head{get;privateset;}privatestringcStr{get;set;}publicBinaryTree(stringconstructStr){this.cStr=constructStr;th......
  • 【LBLD】带权重的随机选择算法
    带权重的随机选择算法528.按权重随机选择不使用二分法:classSolution{private:vector<int>preSum;intN=0;public:Solution(vector<int>&w){srand(time(0));preSum.push_back(0);for(inti=1;i<=w.size();i++){......
  • Java中常用排序算法及示例-冒泡排序、希尔排序、选择排序、插入排序、合并排序、基数
    场景Java中需要对数据进行排序处理,常用的排序算法以及示例进行归纳整理。注:实现1、冒泡排序冒泡排序法又称为交换排序法,原理是从第一个元素开始,比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较。如此扫描一次之后就可以确保最后一个元素位于正确的顺序,接着逐步进......
  • Java中常用算法及示例-分治、迭代、递归、递推、动态规划、回溯、穷举、贪心
    场景1、分治算法的基本思想是将一个计算复杂的问题分成规模较小、计算简单的小问题求解,然后综合各个小问题,得到最终答案。2、穷举(又称枚举)算法的基本思想是从所有可能的情况中搜索正确的答案。3、迭代法(IterativeMethod)无法使用公式一次求解,而需要使用重复结构(即循环)重复执......
  • 算法-回文链表-24
    /***Definitionforsingly-linkedlist.*publicclassListNode{*publicintval;*publicListNodenext;*publicListNode(intx){val=x;}*}*/publicclassSolution{publicListNodeReverseList(ListNodehead){i......
  • 期望最大化算法(EM)简介
    ExpectationMaximization,EM算法是带有隐变量的概率模型参数的极大似然估计(MLE为给定参数,观测数据出现/生成的可能性)。如下为《统计机器学习》中对应EM算法的笔记。观测数据Y和隐变量X合称,完全数据观测数据Y称,不完全数据E步:(期望步)求Q函数(上一轮参数固定,模型参数为变量的......
  • 加密算法
    #include<stdio.h>#include<stdlib.h>#include<stdint.h>#include<string.h>#include<openssl/rsa.h>#include<openssl/err.h>#include<openssl/objects.h>#pragmacomment(lib,"libssl.lib")#pragmac......
  • 二叉树遍历算法分析
    二叉树遍历算法分析前/中/后序遍历算法可以发现这三种遍历算法只有一行代码,也就是输出结点数据域的位置不同前序遍历是先输出数据域再递归到左孩子和右孩子中序遍历是先递归到左孩子等返回的时候输出数据域再递归到右孩子后序遍历是指先递归到左孩子,然后递归到右孩子,最后......
  • COMS3200 算法解答
    COMS3200Assignment12023S1100totalmarks,25%overallcoursemarkDue:15:0019April20231Preface1.1NotesThisdocumentissubjecttochangeforthepurposesofclarification.Changesmadesincetheoriginalreleasewillbehighlightedinred.Please......