单源最短路 Dijkstra 学习笔记

算法实现

Dijkstra是通过贪心来进行实现的。所以不能判定有负边的图。
看一下这张图,我们从1号点开始遍历,且令disti为第i个点到1好点的最短路径。

5
6
12
7
6
11
1
1
2
3
4
5
6

首先我们把已知最短路的点设为长方形,未知的设为圆形即可,那么一号点就是已知的,及dist1=0
接下来,从已知点集到未知点集最短的一个点为点2,及dist2=5
然后一步一步推,如图:

5
6
12
7
6
11
1
1
2
3
4
5
6

然后是4号点最近

5
6
12
7
6
11
1
1
2
3
4
5
6

再就是3号点。

5
6
12
7
6
11
1
1
2
3
4
5
6

这样就可以推下去就可以了。
注意:最短的那个点并不是指边权,比如说6号点,它的值是由dist3+c3,6=8,不仅仅是c3,6

代码实现

#include<cstdio>//采用Dijstra
#include<vector>//朴素
#include<cstring>//使用vector动态数组存储
#define maxn 500039
using namespace std;
int ans[maxn];
int n,m,s,i,j,from;
struct Di{
int to,q;
}f;
vector<Di> q[maxn];
int v[maxn];
int T,minx,a,b;
int main(){
scanf("%d%d%d",&n,&m,&s);
memset(ans,0x3f,sizeof(ans));
ans[s]=0;
for(i=1;i<=m;i++){
scanf("%d%d%d",&from,&f.to,&f.q);
q[from].push_back(f);
}
v[s]=1;
for(int k=1;k<n;k++){//核心 Dijstra
minx=0x7fffffff;
for(i=1;i<=n;i++)
if(v[i])
for(j=0;j<q[i].size();j++)
if(ans[i]+q[i][j].q < minx && !v[q[i][j].to] ){
minx=ans[i]+q[i][j].q;
a=q[i][j].to;
}
v[a]=1;
ans[a]=minx;
}
for(int i=1;i<=n;i++)
if(ans[i]==0x3f3f3f3f)
printf("2147483647 ");
else printf("%d ",ans[i]);
return 0;
}

堆优化-Update 20201106

这里会发现,我们这里有三层循环,大大降低了效率,所以我们需要使用堆来进行优化。
我们看一下Dijkstra的步骤:

  1. 设置起点
  2. 从已知未知集中找到最短的一条路径
  3. 更新这个点的最短路
  4. 重复24

我们发现第2步可以进行优化。
怎么优化呢?
我会zkw非递归式线段树!
我会斐波那契额堆!
我会堆!
我们把所有从已知点集到扩展出的所有点扔近一个堆。当然, dist 最小的在堆顶部就可以了。

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100039
#define maxm 200039
using namespace std;
//#define debug
typedef int Type;
inline Type read(){
Type sum=0;
int flag=0;
char c=getchar();
while((c<'0'||c>'9')&c!='-') c=getchar();
if(c=='-') c=getchar(),flag=1;
while('0'<=c&&c<='9'){
sum=(sum<<1)+(sum<<3)+(c^48);
c=getchar();
}
if(flag) return -sum;
return sum;
}
struct JTZ{
int num,dist;
bool operator > (const JTZ x) const {
return this->dist > x.dist;
}
};
priority_queue<JTZ,vector<JTZ>,greater<JTZ> > q;
int dist[maxn],vis[maxn],n,m,s;
int u,v,w;
int head[maxn],nex[maxm],to[maxm],c[maxm],k;
#define add(x,y,z) c[++k]=z;\
to[k]=y;\
nex[k]=head[x];\
head[x]=k;
void Dij(){
q.push((JTZ){s,0});
dist[s]=0;
while(!q.empty()){
int cur=q.top().num;
q.pop();
if(vis[cur]) continue;
vis[cur]=1;
for(int i=head[cur];i;i=nex[i])
if(c[i]+dist[cur]<dist[to[i]])
if(!vis[to[i]]){
dist[to[i]]=c[i]+dist[cur];
q.push((JTZ){to[i],dist[to[i]]});
}
}
return;
}
int main(){
n=read(); m=read(); s=read();
for(int i=1;i<=m;i++){
u=read(); v=read(); w=read();
add(u,v,w);
}
memset(dist,0x7f,sizeof(dist));
Dij();
for(int i=1;i<=n;i++)
printf("%d ",dist[i]);
return 0;
}
posted @   jiangtaizhe001  阅读(36)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示