堆优化版dijkstra算法分析:
朴素版dijkstra的时间复杂度为O(n^2),主要瓶颈在于第1
步的寻找全局最小值的过程。
可以用小根堆(C++STL priority_queue)对dist
数组进行维护,用O(logn)的时间获取最小值并从堆中删除,用O(logn)的时间执行一条边的扩展和更新。
因此最终我们可在O(mlogn)的时间内实现 Dijkstra
算法。
该算法适用于稀疏图,非负权边图。
代码片段:
int dijk()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
//小根堆定义,PII的第一个变量是距离,第二个变量是点的编号
pq.push({dist[1], 1});//顺序不能倒,pair排序时先first,后second,堆内部默认按照距离排序(二元组第一个变量)
while(pq.size())
{
pii t = pq.top();//选择堆顶 最小距离的点
pq.pop();
int ver = t.y, distance = t.x;
if(st[ver]) continue;//如果被标记过,直接跳过当前循环
st[ver] = true;//标记该点被使用
for(int i=h[ver]; ~i; i=ne[i])//扫描ver号点所有相邻出边
{
int j = e[i];//邻接点编号
if(dist[j]>distance+w[i])
{
//更新,把新的二元组插入堆
dist[j] = distance + w[i];
pq.push({dist[j], j});
}
}
}
if(dist[n]==inf) return -1;
return dist[n];
}
例题:AcWing 850. Dijkstra求最短路 II
时间复杂度:O(m logn)
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef pair<int, int> pii;
#define x first
#define y second
const int N = 1.5e5+10;
int n, m;
int h[N], e[N], ne[N], w[N], idx;
int dist[N], st[N];
void add(int a, int b, int c)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int dijk()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({dist[1], 1});
while(pq.size())
{
pii t = pq.top();
pq.pop();
int ver = t.y, distance = t.x;
if(st[ver]) continue;
st[ver] = true;
for(int i=h[ver]; ~i; i=ne[i])
{
int j = e[i];
if(dist[j]>distance+w[i])
{
dist[j] = distance + w[i];
pq.push({dist[j], j});
}
}
}
if(dist[n]==inf) return -1;
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i=0;i<m;++i)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
add(x, y, z);
}
cout<<dijk()<<endl;
return 0;
}