dijkstra最短路径算法视频_Dijkstra 最短路径算法 秒懂详解

本文介绍了Dijkstra算法,一种时间复杂度为O(n²)的单源最短路径算法。通过实例解释了算法过程,并提供了C++实现,包括邻接矩阵和邻接表两种方式。同时指出该算法不适用于存在负权边的情况,推荐使用Bellman-Ford算法处理负权边问题。
摘要由CSDN通过智能技术生成

想必大家一定会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

图大概是这个样子:

我们以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

dis[0,5,6,∞,∞] minn=3.

然后搜索4号点,map[2][4]=3,原本dis[4]=∞,所以,dis[2]+map[2][4]=5+3=81,minn不更新。

dis[0,5,6,8,∞] minn=3.

接着搜索5号点,map[2][5]=2,5+2=7,7

dis[0,5,6,8,7]

二号点搜完,因为minn是3,继续搜索3号点。

三号点还是按照二号点的方法搜索,发现没有可以更新的,然后搜索四号。

四号搜5号点,发现8+7>5+2,所以依然不更新,然后跳出循环。

现在的估计值就全部为确定值了:

dis[0,5,6,8,7]

这就是每个点到源点一号点的距离,我们来看一下代码:

#include

#include

#include

#include

#include

#include

using namespace std;

int map[110][110];//这就是map数组,存储图

int dis[10010];//dis数组,存储估计值

int book[10010];//book[i]代表这个点有没有被当做源点去搜索过,1为有,0为没有。这样就不会重复搜索了。

int n,m;

void dijkstra(int u)//主函数,参数是源点编号

{

memset(dis,88,sizeof(dis));//把dis数组附最大值(88不是十进制的88,其实很大)

int start=u;//先从源点搜索

book[start]=1;//标记源点已经搜索过

for(int i=1;i<=n;i++)

{

dis[i]=min(dis[i],map[start][i]);//先更新一遍

}

for(int i=1;i<=n-1;i++)

{

int minn=9999999;//这就是刚才所说的minn

for(int j=1;j<=n;j++)

if(book[j]==0 && minn>dis[j])

{

minn=dis[j];

start=j;//找到离源点最近的点,然后把编号记录下来,用于搜索。

}

book[start]=1;

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,但是这个算法有一个坏处,就是出现负权边,这个算法就炸了,要解决负权边,我以后会给大家带来Bell man ford

这个算法的复杂度是O(n²),空间复杂度也是n平方,如果用邻接表来实现,时间复杂度是O(n*m)似乎比n²要大一些,但是空间复杂度会从n平方变成m,少了很多,现在我呈上邻接表的代码,如果不会邻接表的同学可以选择性忽略,自行百度,我可能会出一期邻接表。

#include

#include

#include

#include

#include

#include

using namespace std;

int value[10010],to[10010],next[10010];

int head[10010],total;

int book[10010];

int dis[10010];

int n,m;

void adl(int a,int b,int c)

{

total++;

to[total]=b;

value[total]=c;

next[total]=head[a];

head[a]=total;

}

void dijkstra(int u)

{

memset(dis,88,sizeof(dis));

memset(book,0,sizeof(book));

dis[u]=0;

for(int i=1;i<=n;i++)

{

int start=-1;

for(int j=1;j<=n;j++)

if(book[j]==0 && (dis[start]>dis[j] || start==-1))

start=j;

book[start]=1;

for(int e=head[start];e;e=next[e])

dis[to[e]]=min(dis[to[e]],dis[start]+value[e]);

}

}

int main()

{

cin>>n>>m;

for(int i=1;i<=m;i++)

{

int a,b,c;

cin>>a>>b>>c;

adl(a,b,c);

}

dijkstra(1);

for(int i=1;i<=n;i++)

cout<

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值