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