#include<iostream> #include<cstring> #include<queue> #include<vector> #include<algorithm> usingnamespacestd; typedefpair<int, int> PII; #define IOS \ ios::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0) constint N = 1e6; int h[N], w[N],e[N], ne[N], idx; bool s[N]; int d[N]; int n,m;
voidadd(int a, int b, int c)// 添加一条边a->b,边权为c { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; }
intdijkstra(){ priority_queue<PII,vector<PII>,greater<PII>> heap;// 定义小根堆heap memset(d, 0x3f, sizeof d); d[1] = 0;// 这步不能忘 heap.push({0,1});// 分别存放距离,顶点编号,因为对距离排序 while (heap.size()){ PII t = heap.top(); heap.pop();// 取出堆顶并弹出,已经用过 int ver = t.second,dist = t.first; if (s[ver]) continue;// 找到当前未在s中且距离d最小的点ver if (ver == n) break;// 优化判断 s[ver] = true;// 将ver放入最短路集合s中 for (int i = h[ver]; ~i;i = ne[i]){// 遍历ver的出边 int j = e[i]; if (s[j]) continue;// j以及放入了最短路集合s中,没必要再计算距离 if (d[j] > d[ver] + w[i]){// 更新其他点的距离 d[j] = d[ver] + w[i];// 边松弛 ,这两处的d[ver]可以用dist替代 heap.push({d[j],j});// 更新距离的点插入堆中 } } } if (d[n] == 0x3f3f3f3f) return-1; return d[n]; }
intmain(){ IOS; cin >> n >> m; memset(h, -1, sizeof h); while (m -- ){ int x,y,z; cin >> x >> y >> z; add(x, y, z); } cout << dijkstra() << '\n'; return0; }
时间复杂度:O(m*logn)。
首先看while循环次数,就是q.size() 的大小,q.size()的大小由内层循环q.push()决定,push是在遍历边时才可能发生的,最多等于边数,所以外层最多m次;内层循环,q.pop() 最坏时O(lgm); 总的循环次数: m(lgm) + m; 然后 m < n^2; 所以 lgm < 2lgn; 所以时间复杂度可以写成 O(mlogn); 如果变数m很大,接近n^2的话,就不如朴素的了。