图论 最短路径Dijkstra算法你还不会?一分钟教你弄懂原理。

内容干货十分多,请耐心读阅,做好笔记

原理讲解

这是一张有向图,每两个结点之间路径的权值已经标好,把0当做起始点。
那么,从结点0到结点4的最短距离是多少呢?
我想,通过肉眼观察你应该能找出答案,答案是7,结点0->结点2->结点4
可是,如果这张图在复杂一点呢?
这就需要用到最短路径Dijkstra算法。
如果我们要求两个结点之间的最短路径,除了通过一条边到达的,可不可能有通过两条边到达的路径更短,当然可能,可还有3条边,4条边呢?
我们先换个思路,考虑从结点0只有一条边连接的结点
在这里插入图片描述
从结点0一条边只能到达1,2,3这三个结点,而其中的最短路径为结点0->1长度为2。还有可能有通过2条边从结点0->1比长度2更短的吗?不可能了。因为如果要选第二条边,必须加上第一条边,而第一条边不能选2,而且肯定>2,第一条边就大于长度2,那么加上第二天边肯定也大于长度2。由此我们发现,从结点0到达结点1的最短路径的长度就为2。
但是,如果我们第一次考虑的是从结点0->2的最短路径,那么一条边为长度7,两条边的长度可不可能小于7?可能。因为第一点边7的长度不是最短,可能通过长度2更第二条边相加得到更短的路径。
所以,我们确定从结点0到其他结点的距离,不应该从结点1到结点n,而是应该每次先确定与结点0连接的最短边的结点。这样,此结点的状态可以用绿色标明,表示从初始结点0到它的最短路径已经被确定。而不选最短边则无法用绿色标明,无法确定是不是最短路径。
我们建立一个二位数组表示直接路径长度lujing[][],vis[]表示是否已经确定为从结点0到该结点的最短路径,d[x]表示从结点0到结点x的最短路径长度,
先让d[x]=一条边的lujing[0][x]
此时
lujing[0][1]=2 , , d[1]=2, vis[1]=ture. //最短为true
lujing[0][2]=6 , , d[2]=6, vis[2]=false.
lujing[0][3]=7 , , d[3]=7, vis[3]=false.
lujing[0][4]=max,d[4]=max, vis[4]=false.//max表示无穷大
lujing[1][2]=max,lujing[2][1]=max
lujing[1][3]=3,lujing[3][1]=max
lujing[1][4]=6,lujing[4][1]=max
lujing[2][3]=max,lujing[3][2]=max
lujing[2][4]=1,lujing[4][2]=max
lujing[3][4]=5,lujing[4][3]=max
lujing[i][i]=0,i从0到4
这些可以根据具体题目循环搞定

在这里插入图片描述
此时有个较短的中转站0->1,用它作为中间结点更新从0到其他结点的路径长度。并通过比较新的路径d[1]+lujing[1][x] 与旧的 d[x],
使最短路径d[x]=min(d[x],lujing[0][x])
0->1->3=5,d[1]+lujing[1][3]=5,d[3]=7,所以新的d[3]=5
0->1->4=8,d[1]+lujing[1][4]=8,d[4]=max,所以新的d[3]=5
更新完后,我们可以比较先在除了已经确定的最短路径的d[1],
从未确定最短路径(vis[x]=false)的其它d][x],
也就是从d[2],d[3],d[4]中找到最短连接长度,它就可以被确定为最短路径
d[2]=6
d[3]=7
d[2]=8
可以找到它是d[2]=6,就让vis[2]=ture,
如此循环,可以求出从结点0到每个结点的最短路径,到达不了则d[x]=max

下面是实现代码

for(int i = 1; i <= 4; i++)//一次循环确定一个最短路径d[x,]vis[x]=true
int x = 0; //标记下一个即将确定为最短路径的结点下标x
for(int j = 1; j <= 4; j++)//循环结点
if(vis[j]!=ture&&d[j]) <d [x]) x = j;//不断更改直接路径最短的下标x
vis[x] = ture;//循环完后最短直接路径已被确定
   for(int k = 1; k <= x; k++){
   d[j] = min(d[j], d[x] + lujing[x][j]);//用该点更新最短路径
   }
}

下面是一位博主分享的文章,可以去写道题练练手

第十二届蓝桥杯B组C/C++省赛 最短路径

下面是Dijlstra算法的可视化网站

算法可视化网站

原创不易,点个关注呗!

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

探索中前进two

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值