题解:P3371 【模板】单源最短路径(弱化版)|| Dijkstra 算法详解
其他题解有介绍 SPFA 的,这篇题解主要介绍 Dijkstra 的朴素版本和堆优化的。
什么是 Dijkstra
Dijkstra 算法由荷兰计算机科学家 E. W. Dijkstra 于 1956 年发现,1959 年公开发表。是一种求解非负权图上单源最短路径的算法。
朴素版本
首先先介绍 Dijkstra 的做法。
对于
接下来稍微证明一下这样操作的正确性。\
这里是用到了贪心的思想。\
首先,我们先解释对于目前没有找到最短路径的那些点中为什么要将
综上,此算法正确。
这里给出
void dijkstra(){
for(int i = 1;i<=n;i++){//固定为每一次循环添加一个点
int k=0;//用于存未找到最短路径的那些点中的 dis 值最小者
for(int j = 1;j<=n;j++){//寻找 k 的过程,相信大佬们这部分都懂
if(!k&&!pd[j]){
k=j;
continue;
}
if(!pd[j]&&(dis[k]>dis[j])&&dis[j]!=2147483647) k=j;
}
pd[k]=1;//将 k 加入到已找到最短路径的那些点中
for(int j = 0;j<a[k].size();j++){
dis[a[k][j].v]=min(dis[a[k][j].v],dis[k]+a[k][j].w);//松弛
}
}
}
堆优化
优化的地方就是在上面的找
void dijkstra(){
q.push({0,s});
while(!q.empty()){
if(pd[q.top().y]){
q.pop();
continue;
}
dis[q.top().y]=q.top().x;
pd[q.top().y]=1;
for(int j = 0;j<a[q.top().y].size();j++){
q.push({q.top().x+a[q.top().y][j].w,a[q.top().y][j].v});
}
q.pop();
}
}
注意:Dijkstra 只能用于非负边权的图中,否则无法保证其正确性
例题
算了,这里就不给大家一一列题了,有一个很好的最短路练习提单,大家可以去里面找题写。
哇,好辛苦啊,真的不点个关注再走吗 qwq