堆优化版dijkstra
时间复杂度 $O(mlogn)$, n表示点数, m表示边数
对于为什么要continue的个人理解
- 和朴素版有一点区别是:因为有可能某个点c既是a的邻接点,又是b的邻接点,假设da为5,db为6,ac为3,bc为1,用a更新到c入堆后,b比c小,轮到用b更新,恰好b连着c,c又入了一次堆,经过优先队列排序,堆顶最小的c先出队,后面的c被continue,不用continue也行只是会tle,因为dist已经被最短的c更新过,后面的进不去if,if保证了算法正确性,而冗余的数据被弹出时还要花时间重新排序而朴素版没有堆存储,直接修改dist,所以没有冗余项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int n, m, a, b, c; int h[N], e[N], ne[N], w[N], idx; int dist[N]; bool st[N]; typedef pair<int, int> PII; void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; } int dijkstra() { memset(dist, 0x3f, sizeof dist); dist[1] = 0; priority_queue<PII, vector<PII>, greater<PII>> heap; heap.push({0, 1}); while(heap.size()) { auto t = heap.top(); heap.pop(); int ver = t.second, distance = t.first; if (st[ver]) continue; st[ver] = true; for (int i = h[ver]; i != - 1; i = ne[i]) { int j = e[i]; if (dist[j] > distance + w[i]) { dist[j] = distance + w[i]; heap.push({dist[j], j}); } } } if (dist[n] == 0x3f3f3f3f) return - 1; return dist[n]; } int main() { cin >> n >> m; memset(h, - 1, sizeof h); while (m--) { scanf("%d%d%d" ,&a, &b, &c); add(a, b, c); } int t = dijkstra(); cout << t << endl; return 0; }
|