隐藏页面特效

[Dijkstra+堆优化]

1|0前言


欢迎来到CSP考前复习系列。。。。。。今天要讲的是Dijkstra。。。

当然,如果有任何错误的话,欢迎留言指出哟。。。

2|0算法作用


Dijkstra算法用于解决单源最短路问题,即求取从一个给定的起点出发到其他节点的最短距离。

3|0算法原理


我们首先定义一个数组dis,代表我们选定的起点到其他各个点的距离最小值。

然后,将dis数组中除了起点以外的所有的元素都赋成inf(无限大)。

然后开始扫描起点所连接的点,找出一个直接距离最短的点,加入已生成的树中,并将连接它们的这条边加入最小生成树中。

然后继续,从已有的最小生成树中的所有点出发,找到一个距离最近的,继续加入生成树。

算法结果

算法运行结束后,将会得到一个处理好的数组dis,其中dis[i]代表从起点出发到节点i的最短路长度。

算法实现
朴素方法
这个普通的写法我并不想过多介绍,因为这样做太过于普通,效率非常低。

你可以使用邻接矩阵来存储整个图,然后每次枚举对应的行或列来找到一个距离最近的。

代码也比较简单,这里并不想过多描述。事实上,我一开始就写的堆优化,因此再把它改成朴素算法将会比较多余。

堆优化
堆优化的主要思想就是使用一个优先队列(就是每次弹出的元素一定是整个队列中最小的元素)来代替最近距离的查找,用邻接表代替邻接矩阵,这样可以大幅度节约时间开销。

在这里有几个细节需要处理:

首先来讲,优先队列的数据类型应该是怎样的呢?
我们知道优先队列应该用于快速寻找距离最近的点。由于优先队列只是将最小的那个元素排在前面,因此我们应该定义一种数据类型,使得它包含该节点的编号以及该节点当前与起点的距离。

我们应该在什么时候对队列进行操作呢?
队列操作的地方,首先就是搜索刚开始,要为起点赋初始值,此时必须将起点加入优先队列中。该队列元素的节点编号为起点的编号,该节点当前与起点的距离为00。

那么如果一个节点到起点的最短距离通过其他的运算流程发生了变化,那么如何处理队列中的那个已经存入的元素?
事实上,你不需要理会队列中的元素,而是再存入一个就行了。因为如果要发生变化,只能将节点与起点之间的距离变得更小,而优先队列恰好是先让最小的那个弹出。

因此,轮到某一个队列元素弹出的时候,如果有多个元素的节点编号相同,那么被弹出的一定是节点编号最小的一个。等到后面再遇到这个节点编号的时候,我们只需要将它忽略掉就行了。

注意:dijkstra不能跑有负环的图和最长路(最长路的贪心是错的,自己手玩一下就好)

1 #include <cstdio> 2 #include <queue> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 int n,m,s; 7 int head[100001],dis[100001],cnt; 8 bool vis[100001]; 9 struct qwq{ 10 int from,to,next; 11 long long len; 12 }edge[200001]; 13 void add(int u,int v,int w) 14 { 15 cnt++; 16 edge[cnt].from=u; 17 edge[cnt].to=v; 18 edge[cnt].len=w; 19 edge[cnt].next=head[u]; 20 head[u]=cnt; 21 return; 22 } 23 struct node{ 24 int index,dist; 25 bool operator < (const node &x)const 26 { 27 return dist>x.dist; 28 } 29 }; 30 priority_queue<node> q; 31 int main() 32 { 33 scanf("%d%d%d",&n,&m,&s); 34 for(int i=1;i<=m;i++) 35 { 36 int u,v,w; 37 scanf("%d%d%d",&u,&v,&w); 38 add(u,v,w); 39 } 40 for(int i=1;i<=n;i++) 41 dis[i]=2147483647; 42 dis[s]=0; 43 q.push(node{s,0}); 44 while(!q.empty()) 45 { 46 node x=q.top(); 47 q.pop(); 48 int u=x.index; 49 if(vis[u]) continue; 50 vis[u]=1; 51 for(int i=head[u];i;i=edge[i].next) 52 { 53 if(dis[edge[i].to]>dis[u]+edge[i].len) 54 { 55 dis[edge[i].to]=dis[u]+edge[i].len; 56 q.push(node{edge[i].to,dis[edge[i].to]}); 57 } 58 } 59 } 60 for(int i=1;i<=n;i++) 61 printf("%d ",dis[i]); 62 return 0; 63 }

__EOF__

本文作者风丨铃
本文链接https://www.cnblogs.com/-Wind-/p/10164910.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   风丨铃  阅读(5351)  评论(5编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示