dijkstra算法是经典的贪心算法。基本的想法是,有两个集合S和E,开始S集合中只有一个起点,E集合中有剩下的其他点。遍历E集合中的所有点,找出与起点距离最近的一个点,将其加入集合S,并用该点去更新起点到其他点的最短路径。

由动图结合上面的思路,我们可以看出,算法的基本框架是:
1 1.初始化
2 for i(0 -> n - 1)
3 {
4 2.找出距离起点最近的点
5 3.标记该点加入集合S
6 4.用新加入集合S的点去更新起点到其他点的最短距离
7 }
1.其中初始化包括了距离数组dis,将dis数组初始化为无穷大,将第一个点的距离置为0。
2.循环n - 1次是因为n个点只需添加n - 1个点到集合S,每做一次循环添加一个点,所以是循环n - 1次。
3.标记新点加入集合用一个st数组记录即可。
4.dis[i]表示的是起点s到i的点距离,所以用新点a去更新起点s到其他点(例如b点)的最短路径就是比较dis[a] + (a到b的距离)和 dis[b]的大小,将dis[b]置成两者中的最小值。
5.可以注意的是在伪代码中的2步:找出距离起点最近的点,要遍历剩下的所有点,所以时间复杂度是O(n),但是我们联想到,在一堆数字中找出一个最小值,可以用堆进行优化,时间复杂度是可以由O(n)降到O(logn)的。所以这就是dijkstra的堆优化,可以将时间复杂度为O(mn)降为O(mlogn)。但是在稀疏图中使用较好。稠密图依旧是朴素的dijkstra算法效果更好。
完整代码:
朴素版本:
时间复杂度O(mn)
1 #include <cstring>
2 #include <iostream>
3 #include <algorithm>
4
5 using namespace std;
6
7 const int N = 510;
8
9 int n, m;
10 int g[N][N];
11 int dis[N];
12 bool st[N];
13
14 int dijkstra()
15 {
16 memset(dis, 0x3f, sizeof dis);//初始化
17 dis[1] = 0;
18
19 for (int i = 0; i < n - 1; i ++ )
20 {
21 int t = -1;
22 for (int j = 1; j <= n; j ++ )//找出距离起点最近的点
23 if (!st[j] && (t == -1 || dis[t] > dis[j]))
24 t = j;
25 st[t] = true;//标记加入集合S
26
27 for (int j = 1; j <= n; j ++ )//用该点去更新其他点
28 dis[j] = min(dis[j], dis[t] + g[t][j]);
29
30 }
31
32 if (dis[n] == 0x3f3f3f3f) return -1;
33 return dis[n];
34 }
35
36 int main()
37 {
38 cin >> n >> m;
39
40 memset(g, 0x3f, sizeof g);
41 while (m -- )
42 {
43 int a, b, c;
44 cin >> a >> b >> c;
45
46 g[a][b] = min(g[a][b], c);
47 }
48
49 cout << dijkstra() << endl;
50
51 return 0;
52 }
53
54
堆优化版本:
时间复杂度O(mlogn)
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 = 1e5 + 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 PII t = heap.top();
32 heap.pop();
33
34 int ver = t.second, distance = t.first;
35
36 if (st[ver]) continue;//如果已经加入集合过就跳过
37 st[ver] = true;
38
39 for (int i = h[ver]; i != -1; i = ne[i])
40 {
41 int j = e[i];
42 if (dist[j] > distance + w[i])
43 {
44 dist[j] = distance + 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 cin >> n >> m;
57
58 memset(h, -1, sizeof h);
59 while (m -- )
60 {
61 int a, b, c;
62 cin >> a >> b >> c;
63 add(a, b, c);
64 }
65
66 cout << dijkstra() << endl;
67
68 return 0;
69 }
来源:https://www.cnblogs.com/1-0001/p/12229393.html