图论——最短路算法笔记 djkstra
一. 单源最短路
1. 边权为正
(1)朴素版dijkstra算法(基于稠密图)
算法原理:维护一个S集合,存放已经确定最短距离的点(从指定起点到当前点),循环n次,每次从S集合外,取出距离最近的点 t,将 t 加进S集合,然后用 t 点,更新起点到其他所有点的距离
1 // dijkstra朴素版 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #define N 510 6 using namespace std; 7 8 int g[N][N], dist[N]; 9 bool st[N]; 10 int n, m; 11 12 int dijkstra() 13 { 14 memset(dist, 0x3f, sizeof dist); 15 dist[1] = 0; 16 // st[1] = true; 不能在初始化的时候这样做,因为dist[1]实际上还有待进一步确定 17 18 19 for (int i = 0; i < n; i ++) // 循环n次,遍历每个点,每遍历一个点,这个点到1号点的最短距离就唯一确定了 20 { 21 int t = -1; // 用-1初始化t,t最后需要返回的使最近的点的下标 22 for (int j = 1; j <= n; j ++) // 找到st集合以外的点(还未确定到1号点的最短距离)中离1号点最近的点 23 { 24 if(!st[j] && (t == -1 || dist[j] < dist[t])) t = j; 25 } 26 27 if(t == n) break; // 如果n号点到1号点的距离已经唯一确定了,就可以直接break 28 29 st[t] = true; // 到这一步t号点到1号点的距离就已经唯一确定了(加入集合st) 30 31 for (int j = 1; j <= n; j ++) // 用最新确定的t号点来更新所有点到1号点的距离 32 { 33 dist[j] = min(dist[j], dist[t] + g[t][j]); // 在(原值)与(先经过t点再从t点到j点的路径长度)二者之间取最小值 34 } 35 } 36 37 if(dist[n] == 0x3f3f3f3f) return -1; // 代表1号点与n号点不连通 38 return dist[n]; 39 } 40 41 int main() 42 { 43 cin >> n >> m; 44 45 memset(g, 0x3f, sizeof g); 46 47 for (int i = 0; i < m; i ++) 48 { 49 int a, b, c; 50 scanf("%d%d%d", &a, &b, &c); 51 g[a][b] = min(g[a][b], c); // 在重边中保留最短的那一条 52 } 53 54 int t = dijkstra(); 55 56 printf("%d\n", t); 57 58 return 0; 59 }
(2)dijkstra算法(堆优化版)
1 // dijkstra堆优化版 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <queue> 6 #define N 150010 7 using namespace std; 8 9 int n, m; 10 int idx, h[N], e[N], ne[N], w[N]; // w(weight)记录每条边的权重(边的长度) 11 typedef pair<int, int> PII; 12 int dist[N]; 13 bool st[N]; // 标记第i号点到1号点的最短距离是否唯一确定 14 15 void add(int a, int b, int c) 16 { 17 e[++ idx] = b, ne[idx] = h[a], h[a] = idx, w[idx] = c; 18 } 19 20 int dijkstra() 21 { 22 memset(dist, 0x3f, sizeof dist); 23 dist[1] = 0; 24 25 // 用来存储所有的未确定的点及其距离,每次以第一关键字(点到1号点的距离)为排序顺序,返回最小距离(小根堆) 26 // 但是优先队列不能修改某个值,所以每次只能把更新的值push进去,再用一个st数组来记录i号点是否已经确定最短距离 27 priority_queue<PII, vector<PII>, greater<PII>> heap; 28 heap.push({0, 1}); 29 30 while(heap.size()) // 代替朴素版中的每次找到未确定的点中距离1号点最近的点 31 { 32 PII t = heap.top(); // 找出来作为新确定的 33 heap.pop(); 34 35 int id = t.second, distance = t.first; 36 37 if(id == n) break; // 如果n号点的最短距离已经唯一确定了,就break 38 if(st[id]) continue; // 如果这个点已经是确定过的点 39 40 st[id] = true; 41 for (int i = h[id]; i != 0; i = ne[i]) // 通过相连的边来更新所有关联的点 42 { 43 int tmp = distance + w[i]; 44 int j = e[i]; 45 if(st[j]) continue; // 如果是已经确定的点-->有回路 46 if(dist[j] > tmp) 47 { 48 dist[j] = tmp; 49 heap.push({tmp, j}); 50 } 51 } 52 } 53 54 if(dist[n] == 0x3f3f3f3f) return -1; // 1号点与n号点不连通 55 return dist[n]; 56 } 57 58 int main() 59 { 60 cin >> n >> m; 61 62 for (int i = 0; i < m; i ++) 63 { 64 int a, b, c; 65 scanf("%d%d%d", &a, &b, &c); 66 add(a, b, c); 67 } 68 69 printf("%d\n", dijkstra()); 70 71 return 0; 72 }
浙公网安备 33010602011771号