堆优化版dijkstra算法,时间复杂度O(nlogm)
算法思路:
//稀疏图,堆优化
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef pair<int, int> PII; //
const int N = 2e5 + 5;
int n, m;
int h[N], w[N], e[N], ne[N], idx; //带权值邻接表
int dist[N];
bool st[N];
void add(int a, int b, int c) //在a到b之间增加一条权重为c的边
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
int dijkstra()
{
memset(dist, 0x3f, sizeof dist); //dist数组初始化
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
/*
小根堆无法实现数据的替换,只能单方面插入,因此在找到一个更优解时,旧的解也会存在
小根堆中。因为小根堆的有序性,更优解一定在旧的解之前被操作,只需要记录每个点的编
号,在每次取点时跳过操作过的点即可。
*/
heap.push({0, 1}); //1号点的距离是0
while(heap.size())
{
auto t = heap.top(); //取堆顶元素,即最短距离
heap.pop();
int ver = t.second, distance = t.first;
if(st[ver]) continue;
//当前ver号点被操作过,说明现在的distance是被替换过的distance,需要跳过
st[ver] = true; //标记操作过的点
//遍历ver节点的所有出边,更新之前节点的最短路径
for(int i = h[ver]; i != -1 ; i = ne[i])
{
int j = e[i];
//distance + w[i] == dist[ver] + g[ver][j]
if(dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
heap.push({dist[j], j}); //更新最短路
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
/*
在dijkstra算法中总是取最短的边操作,所以即使有重边也会取最短的一条,
因此输入的时候不需要判断重边
*/
while( m -- )
{
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
}
cout << dijkstra();
return 0;
}