Dijkstra算法基础入门

本文介绍了Dijkstra算法的基础知识,包括算法的C语言实现代码,核心解析,动态过程和实战应用。文章详细讲解了如何构建图,更新最短路径,并通过实例展示了算法的运行过程。此外,还提供了一个Dijkstra算法的实际问题解题示例。

Dijkstra算法基础入门

前言

Dijkstra是一种寻找最短路径的算法,虽然思维容易理解,但入门稍有难度。为了方便以后理解,于是写下这篇文章。若文章含有错误,欢迎各位纠正QwQ


1.Dijkstra的C代码

为了方便大家复制,就先把代码放这了

//#define INF    0x7f7f7f7f
//#define MAXSIZE 1000;  
//int map[MAXSIZE][MAXSIZE], dp[MAXSIZE], used[MAXSIZE]; 
//INF:int型最大值
//map:存储各个节点之间的距离
//dp:存储当前最短路径
//num:所有节点个数
//used:记录是否建立了最短路径
//index:访问节点的索引值
void Dijkstra ()  {  
    int i, j ;  
    int min, index;  
    memset (used, 0, sizeof (used)) ;   
    for (i = 1 ; i <= num ; ++i)	dp[i] = map[0][i] ;  
    for (i = 1 ; i <= num ; ++i) {  
        min = INF ;  
        index = 0 ;       
        for (j = 1 ; j <= num ; ++j)  
            if (used[j]==0&& dp[j] < min){  
                index = j ;  
                min  = dp[j] ;  
            }  
        used[index] = 1 ;  
        for (j = 1 ; j <= num ; ++j)
			if (used[j]==0&& dp[index] + map[index][j] < dp[j])	
				dp[j] = dp[index] + map[index][j] ;  
	} 
}

2.Dijkstra核心解析

1.构建map(对数据结构了解可直接跳过)

假如我们得到如下一堆数据(各个节点之间的距离)

A↔D:6

A↔B:3

B↔D:2

B↔E:5

B↔C:3

E↔F:5

将数据化成如下二叉树

image-20230309223449245

从图中可以看出A与A之间的距离显然为0,A与B、D相连,距离分别是3、6,但C、E、F均不与A相连,为了能够表示其他节点不与A相连,于是我们不妨将A与不相连节点之间的距离设为∞,(即为代码中的INF),则得到如下一组数据

0	3	INF	6	INF	INF	

同样我们分别对其他节点分析,可得到另外几组数据,将这几组数据汇聚在一起,就是map(如下表格)

03INF6INFINF
30324INF
INF30INFINFINF
62INF0INFINF
INF4INFINF05
INFINFINFINF50
2.更新dp[i]

假设我们要求某节点与目标节点的dp[i](在遍历过的节点中取得的最短的路径),总共有两种情况,第一种是与[已经确定的最短路径](遍历完所有节点都不会再找到更短的路径)的节点直接相连,第二种是直接与目标节点相连。

image-20230310181209490

这时可能有人发出疑问:假如是有多条路径都比节点直接与目标节点相连的距离要短该怎么求?(如下图)

image-20230310184943074

其实解决方法很简单,因为dp中存储的就是[当前最短的路径],已经包含了第二种情况,我们只要将dp中存储的[当前最短路径]和第一种情况的路径相比就行了,哪个路径更短,则取较短的路径为dp[i],给出以下公式

dp[i]=min{dp[i],dp[m]+map[m][i]}
注:m为已确定[最短路径]的节点。
3.确定最短路径

既然知道怎么求[当前最短路径],那么如何将该节点的最短路径确定下来?解决方法就是[按最短路径从小到大来确定],从求[当前最短路径]可以看出影响该节点的只有比它更短路径的节点(之前图中的红、黄、蓝节点的路径均比紫色节点的路径短),给出以下结论

如果dp中未确定的路径都不小于它的路径,那么此时该节点的最短路径则确定下来

3.Dijkstra动态过程

首先遍历到B节点,B节点满足[未确定最短路径]和[小于min]两个条件,将3赋值给min

Dijktra1

之后遍历到D节点时,虽然满足[未确定最短路径],但min此时的值为3,即不满足[小于min]这个条件,故跳过D点

Dijktra4

最后遍历C、E、F节点时,同样发现不满足[小于min]这个条件,对全过程进行分析,最后筛选得到B节点符合条件,故把它与A之间的路径确定为最短路径(如果不懂,可以回到上面看结论)

Dijktra3

每当有一个最短路径被确定,我们就需要更新一次dp

Dijktra5

重新寻找符合两个条件的节点,确认最短路径,然后更新dp,重复此步骤。(先确定C还是D无所谓,因为两者在当前的最短路径相等)

Dijktra6

4.Dijkstra算法实战

题目链接:zzulioj1263:一个人的旅行

样例输入

6 2 3
1 3 5
1 4 7
2 8 12
3 8 4
4 9 12
9 10 2
1 2
8 9 10

样例输出

9

Dijkstra算法参考代码

#include <stdio.h> 
#include <string.h>  
#include <stdlib.h>  
   
#define max(a, b) (((a) > (b)) ? (a) : (b))  
#define min(a, b) (((a) < (b)) ? (a) : (b))  
   
#define infinity    0x7f7f7f7f  
#define minus_inf    0x80808080  
   
#define MAXSIZE 1009  
   
int road, neigh, dest, cityNum, minTime ;  
int map[MAXSIZE][MAXSIZE], dp[MAXSIZE], used[MAXSIZE], want[MAXSIZE] ;  
   
void dijkstra ()  
{  
    int i, j ;  
    int minPath, iminPath ;  
    memset (used, 0, sizeof (used)) ;   
    for (i = 1 ; i <= cityNum ; ++i) dp[i] = map[0][i] ;  
    for (i = 1 ; i <= cityNum ; ++i)  {  
        minPath = infinity ;  
        iminPath = 0 ;     
        for (j = 1 ; j <= cityNum ; ++j)  
            if (!used[j] && dp[j] < minPath)  {  
                iminPath = j ;  
                minPath  = dp[j] ;  
            }  
        used[iminPath] = 1 ;  
        for (j = 1 ; j <= cityNum ; ++j) if (!used[j] && dp[iminPath] + map[iminPath][j] < dp[j]) dp[j] = dp[iminPath] + map[iminPath][j] ;  
    }
    minTime = dp[want[1]] ;  
    for (i = 2 ; i <= dest ; ++i)    minTime = min (minTime, dp[want[i]]) ;  
}  
   
int main ()  
{  
    int i, j ;  
    int a, b, c ;  
    while (scanf ("%d%d%d", &road, &neigh, &dest) != EOF){  
        memset (map, infinity, sizeof (map)) ;  
        cityNum = 0 ;  
        for (i = 1 ; i <= road ; ++i){  
            scanf ("%d%d%d", &a, &b, &c) ;  
            map[a][b] = map[b][a] = c ;  
            cityNum = max (cityNum, max (a, b)) ;  
        }  
        for (i = 1 ; i <= neigh ; ++i){  
            scanf ("%d", &a) ;  
            map[0][a] = map[a][0] = 0 ;  
        }  
        //以上步骤实现了构建map
        for (i = 1 ; i <= dest ; ++i) 
            scanf ("%d", &want[i]) ;  
        dijkstra () ;  
        printf ("%d\n", minTime) ;  
    }  
    return 0 ;  
} 

参考相关文章链接:

1、Dijkstra算法详解 通俗易懂

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kk_阿白

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

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

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

打赏作者

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

抵扣说明:

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

余额充值