dijkstra算法是用来解决不带负权图上的最短路径问题,从学习这个算法来,写过最朴素的dijkstra,时间复杂度达O(N^2),也写过看似高大上的堆优化dijkstra,时间复杂度因为利用堆找最小值提高效率至O(Mlogn)。
多年来代码风格不停在变,今天在此又重新写了一遍,只为能充分利用C++STL,利用C++在语言上的优势,使堆优化版本写起来优美又简洁。
下面附上代码模版
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200002;
const int MAXM = 400004;
int n,m,total=0,head[MAXN];
struct node{
int v;
int next;
int w;
};
//利用STL优先队列实现堆上找最小值,因为堆默认是大根堆,为了达到小根堆的效果,入距离时,入其负值。
//利用pair这个解决两个数捆绑成一个对象的问题,其中第一个对象是距离,第二个是编号。
priority_queue< pair<long long ,int> >q;
long long dis[MAXN]; //dis[i]存从1至i的最小值。
bool vis[MAXN];
node edge[MAXM*2];//存所有的边
//链式前向星存边 ,非常简洁的写法
void addEdge(int u,int v,int w){
edge[++total]=(node){v,head[u],w};
head[u] = total;
}
void duidij(){
//初始化 距离数组为正无穷,并对起点距离设为0,起点入队列
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[1] = 0;
q.push(make_pair(0,1));
while(q.size()){
int u = q.top().second; //取堆中最小值编号
q.pop();//出堆
if(vis[u]) continue;
vis[u] = true;//设置该编号已被选做最小值作为起点
for(int i= head[u];i;i = edge[i].next){//枚举与u相连的所有边
int v = edge[i].v,w = edge[i].w;
if(dis[v] > dis[u] + w){//寻找可以松弛的边
dis[v] = dis[u] + w; //更新距离
q.push(make_pair(-dis[v],v));//入堆
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 1;i<= m;i++){
int x,y,z;
cin >> x >> y >> z;
addEdge(x,y,z);addEdge(y,x,z);//无向图需要存两遍
}
duidij();
cout << dis[n];
return 0;
}