2023年7月30日发(作者:)
Dijkstra最短路径算法秒懂详解 想必⼤家⼀定会Floyd了吧,Floyd只要暴⼒的三个for就可以出来,代码好背,也好理解,但缺点就是时间复杂度⾼是O(n³)。 于是今天就给⼤家带来⼀种时间复杂度是O(n²),的算法:Dijkstra(迪杰斯特拉)。 这个算法所求的是单源最短路,好⽐说你写好了Dijkstra的函数,那么只要输⼊点a的编号,就可算出图上每个点到这个点的距离。 我先上⼀组数据(这是⽆向图): 5 6 1 2 5 1 3 8 2 3 1 2 4 3 4 5 7 2 5 2图⼤概是这个样⼦:Dijkstra 算法是⼀种类似于贪⼼的算法,步骤如下:1、当到⼀个时间点时,图上部分的点的最短距离已确定,部分点的最短距离未确定。2、选⼀个所有未确定点中离源点最近的点,把他认为成最短距离。3、再把这个点所有出边遍历⼀边,更新所有的点。下⾯模拟⼀下:我们以1为源点,来求所有点到⼀号点的最短路径。先建⽴⼀个dis数组,dis[i]表⽰第i号点到源点(1号点)的估计值,你可能会问为什么是估计值,因为这个估计值会不断更新,更新到⼀定次数就变成答案了,这个我们⼀会再说。然后我们在建⽴⼀个临界矩阵,叫做:map,map[i][j]=v表⽰从i到j这条边的权值是v。dis初始值除了源点本⾝都是⽆穷⼤。源点本⾝都是0.先从1号点开始。⼀号点,map[1][2]=5,⼀号点离2号点是5,⽐⽆穷⼤要⼩,所以dis[2]从⽆穷⼤变成了5。顺便,我们⽤minn记录距离1号点最短的点,留着以后会⽤。dis[0,5,∞,∞,∞]。minn=2。然后搜到3号点,map[1][3]=8,距离是8,⽐原来的dis[3]的∞⼩,于是dis[3]=8。但是8⽐dis[2]的5要⼤,所以minn不更新。dis[0,5,8,∞,∞]接着分别搜索4,5号点,发现map[1][4],map[1][5]都是∞,所以就不更新。现在,dis数组所呈现的明显不是最终答案,因为我们才更新⼀遍,现在我们开始第⼆次更新,第⼆次更新以什么为开始呢?就是以上⼀次我们存下来的,minn,相当于把2当源点,求所有点到它的最短路,加上它到真正的源点(1号点)的距离,就是我们要求的最短路。从2号点开始,搜索3号点,map[2][3]=1,原本dis[3]=8,发现dis[2]+map[2][3]=5+1=6
for(int j=1;j<=n;j++) dis[j]=min(dis[j],dis[start]+map[start][j]);//以新的点来更新dis。 }}int main(){ cin>>n>>m; memset(map,88,sizeof(map)); for(int i=1;i<=m;i++) { int a,b,c; cin>>a>>b>>c; map[a][b]=c; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i==j) map[i][j]=0; dijkstra(1);//以1为源点。 for(int i=1;i<=n;i++) cout<
dijkstra(1); for(int i=1;i<=n;i++) cout< ⼀年多了,⾝为⼀个OIer,经历了太多。当年那么畏惧的Dijkstra、邻接表,现在已经是信⼿拈来。那个暑假,因为Djkstra名字的朗朗上⼝,讲⾃⼰名字改为了Dijkstra,但是逐渐因为SPFA的可处理负权边,也将Dijkstra,淡忘。如今突然想起,加⼊了堆优化,有⼈说:⼀道题如果边权没有负数,那么⼀定是在卡SPFA。这时候就⽤到了堆优化的Dijkstra。⼀年前提到,朴素的Dijkstra时间复杂度是n^2,被SPFA的m*常数吊打,但是,经过堆优化,Dijkstra的时间复杂度能达到nlogn,如果这个图特别稠密的话,也就是m特别⼤(⽐如完全图就是n^2),那么nlogn是要⼩于m的,这就⽤到了Dijkstra⾸先堆优化怎么优化?观察上⾯的代码,每次循环中都再嵌套⼀个循环求dis值最⼩的点。这⾥,我们可以⽤⼀个优先队列,每当搜索到⼀个新点,扔到优先队列⾥⾯,这样每次就取队⾸的绝对是最优值。这样可以省去for循环。#include ,greater > Q;//优先队列优化inline void adl(long long a,long long b,long long c){ total++; to[total]=b; val[total]=c; nxt[total]=head[a]; head[a]=total; return ;}inline void Dijkstra(){ REP(i,1,n) dis[i]=2147483647; dis[s]=0; (P(0,s)); while(!()){ long long u=().second;//取出dis最⼩的点 ();//弹出 if(vis[u]) continue; vis[u]=1; for(long long e=head[u];e;e=nxt[e]) if(dis[to[e]]>dis[u]+val[e]){ dis[to[e]]=dis[u]+val[e]; (P(dis[to[e]],to[e]));//插⼊ } } return ;}int main(){ in(n),in(m),in(s); long long a,b,c; REP(i,1,m) in(a),in(b),in(c),adl(a,b,c); Dijkstra(); REP(i,1,n) printf("%lld ",dis[i]);}
发布者:admin,转转请注明出处:http://www.yc00.com/web/1690722200a407751.html
评论列表(0条)