堆优化版Dijkstra求最短路
思路:上一篇博客介绍的方法每次要找出最小值来更新下一次,而我们可以将每次更新的值直接放到升序的优化队列当中去,就可以少一个循环,将这一步的时间复杂度优化到O(1)。
建议结合上一篇博客一起看,理解这两个方法到底有什么本质的不同。
上代码:
#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
#include <algorithm>
using namespace std;
typedef pair<int,int>PII;
const int N = 1e6 + 10 , M = 2 * N;
priority_queue<PII,vector<PII>,greater<PII> > heap;
int h[N] , e[M] , w[N] , ne[M] , idx;
int dist[N];
bool st[N];
int n,m;
void add(int a, int b, int c)//稠密图用邻接表来存储图。
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx ++;
}
int Dijstra()
{
dist[1] = 0;//首先更新起点到起点的距离为0。
heap.push({0,1});//将这个点放到优化队列中去。第一个点代表距离,第二个点代表数字编号。
while(!heap.empty())
{
PII t = heap.top();//取出对队头。(升序排列优化队列队头就是最小值)
heap.pop();//将队头删掉
if(st[t.second]) continue;//判断如果这个点已经确定最小值了,就直接跳过这个点。
for(int i = h[t.second] ; i != -1 ; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[t.second] + w[i])//比较现在准备更新的这个点和上一次更新的点那个小。
{
dist[j] = dist[t.second] + w[i];//每次将较小的值更新,如果比上次大就不更新。
heap.push({dist[j] , j});//将每次更新的每个点放到优化队列中去。
}
}
st[t.second] = true;//标记这个点已经确定最小值。
}
if(dist[n] == 0x3f3f3f3f) return -1;//如果要求的点一直没有更新,说明走不到这个点。
return dist[n];//否则返回该点最后更新到的距离即为该点到起点的最短距离。
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
memset(dist,0x3f,sizeof dist);
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
cout<<Dijstra()<<endl;
return 0;
}