dijkstra算法详解
dijkstra用于在带权无负环的图中寻找单源最短路径。
怎么样,读完了这句话之后是不是很晕?其实很好理解,解释一下两个新名词,无负环就是没有负数的环,例如:
图中就存在负环,实际上在这个图中无法存在最短路的定义,例如要求从B到C的最短路,先经过A绕一圈答案为 \(-5\),但是再绕一圈答案为 \(-7\),再绕一圈答案为 \(-9\)……显然,在存在负环的情况下,难以存在最短路的定义。
单源最短路很好理解,就是从一个点到其他点的最短路,而全源最短路为从任一点到其他点的最短路。
dijkstra算法思路
利用贪心策略,先给个图
请注意!从A点到B点的最短路不一定是A与B的直接路径,例如图中从1点到2点的最短路为 \(2\) 而不是 \(3\),可以先经过5号点在到达2号点。
dijkstra算法的主要思路就是从一个点出发对其他节点不停做松弛操作。
什么是松弛操作呢?听起来好高大上,其实说白了就是句废话:如果此时到达这个点的最短路比原来更短就更新。
例如从1号点出发,用 \(dis_i\) 表示到达 \(i\) 点的最短路径,初始时图为(圆内用序号+\(dis_i\) 表示当前点,如第一个点的 \(dis_i\) 为5表示为 \(1-5\) ):
此时我们发现1号点可以对2、3、4、5号点进行松弛操作,于是便将 \(dis_4\) 更新为 \(2\),将 \(dis_5\) 更新为 \(1\),将 \(dis_2\) 更新为 \(3\),将 \(dis_3\) 更新为 \(4\),再用这一轮得到的点继续去松弛别的点。
是的,一轮松弛就结束了!dijkstra算法的原理就是一直重复以上操作直到无法松弛为止。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5;
int a[N][N],dis[N],n,m,s;
bool vis[N];
priority_queue<int> q;
void dfs(int beg){
while(1){
int k=0;
for(int i=1;i<=n;i++)
if(!vis[i]&&dis[i]<=dis[k]) k=i;//寻找最小值
if(!k) return ;//无法继续松弛就返回
vis[k]=1;//标记
for(int i=1;i<=n;i++){
if(dis[i]>=dis[k]+a[k][i]){
dis[i]=dis[k]+a[k][i];//松弛
}
}
}
}
int main(){
memset(a,0x3f,sizeof a);
cin>>n>>m>>s>>e;//n个节点,m条边,s为起点,e为重点
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
if(u==v) continue;//删自环
a[u][v]=min(a[u][v],w);//删重边
}
memset(dis,0x3f,sizeof dis);
dis[s]=0;//初始化
dfs(s);
cout<<dis[e];
return 0;
}
该算法的时间复杂度为 \(O(n^2)\)。
很明显这个算法的时间复杂度我们是无法接受的,考虑优化。
代码中动态维护了最小值,这个算法可以用堆来实现,不会使用堆的可以参考这篇博客
解决了这个问题,该算法的时间复杂度可以降到 \(O(n log_n)\)。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int n,m,s;
struct node{
int to,val;
bool friend operator < (const node &x,const node &y){
return x.val>y.val;//重载运算符
}
};
vector<node> a[N];
int dis[N];
bool vis[N];
void dijkstra(){
priority_queue<node> q;//使用STL的优先队列实现堆
q.push({s,0});
while(!q.empty()){
node t=q.top();
q.pop();
if(!vis[t.to]){
vis[t.to]=true;
for(auto p:a[t.to]){
if(dis[p.to]>dis[t.to]+p.val){
dis[p.to]=dis[t.to]+p.val;//进行松弛操作
q.push({p.to,dis[p.to]});//将新的节点加入队中
}
}
}
}
}
int main(){
cin>>n>>m>>s>>e;
memset(dis,0x3f,sizeof dis);
dis[s]=0;//初始化
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
a[u].push_back({v,w});
}
dijkstra();
cout<<dis[e];
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】