朴素版Dijkstra(最短路径)算法

一、图的知识框架

在这里插入图片描述
在这里插入图片描述

图的相关概念非常多,本篇只着重讲解下图所包含的内容。有了以下的内容作为基础,就已经能够学习Dijkstra算法。

在这里插入图片描述

二、基础知识

1、图的定义

关联一下之前学过的单链表和树,单链表是一对一的关系,树是一对多的关系,而图是多对多的关系,每个顶点都可以和其他多个顶点相关联。

图的严格定义:在这里插入图片描述

注:

  • 边也可以叫成 弧

  • 树可以是空树,但图不能为空,一个图至少要有一个点,可以没有边。

2、有向图 和 无向图 和 自环

图中所有边都没有方向的图是无向图
图中所有边都有方向的图是有向图

  • 无向图是特殊的有向图

3、无权图 和 带权图

  • 无权图可看作所有边权值都为1的带权图

4、稠密图 和 稀疏图

设一个图中:点数为n,边数为m

稠密图:m与n^2是一个级别

稀疏图:m与n是一个级别

如:题目给出测试点的范围是:1<=n<=500

              1<=m<=100000

这显然是一个稠密图。

5、邻接矩阵存图

讲了这么多概念,那一个图体现在代码里面是什么样子?邻接矩阵故名思意,用一个矩阵存图。

  • 对于一个有n个顶点的无权图,创建整型数组g[n][n],若第 i 个点到第 j 个点之间存在边,则令g[i-1][j-1]的值为1,反之,值为0。用0和1表示两点之间是否有边。
  • 对于有n个定点的带权图,同样使用g[n][n]来存储,若第 i 个点到第 j 个点之间存在权值为weight的边,则令g[i-1][j-1]的值为weight,若不存在边,则赋为 +∞
  • 邻接矩阵适合存储稠密图。因为矩阵的大小只与图的点数有关,与边数无关,只要点数固定,即使图再怎么复杂也能够用同一个矩阵存储,不需要耗费额外的内存空间。

三、Dijkstra(最短路径)算法

1、原理

Dijkstra算法是基于贪心的思想,每一步都找当前情况下的最优解,那么最后找出来的就是整体的最优解。Djkstra算法的严格证明不需要大家掌握,只要会用它解决问题即可。所以本文讲解的重点是Dijkstra算法的步骤。

2、朴素版Dijkstra算法的适用情况

  • 求单源最短路的情况,即任意一点到源点之间的最短路
  • 所有边权都是正数
  • 稠密图

3、算法步骤

以n个点的有向有权图为例:

  • 初始化所有点到源点的距离:开始只有源点的距离确定,为0,其他点的距离初始化为正无穷
  • 迭代n次
  • 每次确定一个点到起点的最短路。
    确定哪个点呢?是当前还没确定最短路径的点中,到起点距离最短的点。这个距离一定就是该点到源点的最短路,这里就是贪心的思想。
  • 确定这个点的最短距离之后,用这个点 来更新其他点到源点的最短距离。
    一次迭代结束。
  • 经过n次迭代,就可以确定n个点到源点的最短路。那么源点到终点的最短路也就确定了。

下面看一个例子:
在这里插入图片描述

4、代码实现

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数n 和 m
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。

数据范围

1≤n≤500,
1≤m≤10^5,

输入样例:

3 3
1 2 2
2 3 1
1 3 4

输出样例:

3

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>

#define N 510
#define INF 0x3f3f3f3f
//这里涉及到无穷大为什么取0x3f3f3f3f的问题,可以查看下面的博客
//https://blog.csdn.net/m0_51551385/article/details/121522095

int n,m;//n为点数,m为边数
int g[N][N];//g为存储图的邻接矩阵
int dist[N];//dist[i]为点i到源点的距离
int st[N];//st[i]为1表示该点的最短距离已经确定,为0表示该点的最短距离还未确定

int dijkstra()
{
    memset( dist , 0x3f , sizeof(dist) );//初始化距离,对应Dijkstra算法的第一步
    dist[1] = 0;//源点到自己的最短距离为0

    for( int i = 0 ; i < n ; i++ )//对应第二步,进行n次迭代,每次确定一个点的最短路径
    {			   //用t表示当前选择的要确定最短路的点,t取值要求:不能是已经确定最短路的点
        int t = -1;//t = -1表示开始还没选择任何点
        for( int j = 1 ; j <= n ; j++ )//遍历所有点,找到符合条件的点
        {
            if( st[j] == 0 && (t == -1 || dist[t] > dist[j]) )//st[j] == 0确保t的最短路径还没有被确定
                t = j;					 //t == -1保证t 一定 是第一个遍历到的最短路没有确定的点
        }								 //dist[t] > dist[j]保证 t 是当前 到源点距离最短的点
        
		//t的最短距离已经确定,st数组标记为1
        st[t] = 1;
		
		//用t更新其他点到源点的最短距离
        for( int j = 1 ; j <= n ; j++ )
        {
            dist[j] = fmin( dist[j] , dist[t] + g[t][j] );
        }
    }

    if( dist[n] == INF )
        return -1;
    else
        return dist[n];
}

int main()
{
    scanf("%d %d",&n,&m);//输入点数和边数

    memset( g , 0x3f , sizeof(g) );//初始化邻接矩阵

    for( int i = 1 ; i <= n ; i++ )//每个点到自己距离为0
    {							   //因为输入的点的编号从 1 开始,所以为了后续操作方便,第0行 和 第0列舍弃,直接从第一行第一列开始存
        g[i][i] = 0;
    }

    while( m-- )//输入m条边
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        g[a][b] = fmin( g[a][b] , c);//可能有重边,所以只保留距离最短的边即可
        //g[b][a] = g[a][b];如果是无向图的话采用这种方式来建图
    }

    int t = dijkstra();

    if( t == -1 )
        printf("-1");
    else
        printf("%d",t);

    return 0;
}

5、时间复杂度:O(n^2)

四、作业

利用最短路径Dijkstra算法解决实际问题,校园中的最短路问题。
在这里插入图片描述

说明:

  • 起点(源点)和终点的选取是随意的,只要能用Dijkstra算法输出他们的最短路即可。
  • 不要求手动输入,直接在main函数中建图即可。

五、拓展

下图中列举了所有求最短路径的情况,有兴趣的可以自行学习。
在这里插入图片描述

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Djkstra算法是一种用于解决图中单源最路径问题的算法。它通过计算从一个起始节点到所有其他节点的最路径距离,并保存路径信息,以便能够找到最路径。Djkstra算法的实现可以在MATLAB中完成。 在MATLAB中,可以使用以下步骤实现Djkstra算法: 1. 首先,需要定义一个环境矩阵map,它描述了图中各个节点之间的连接情况。例如,可以将0表示为节点之间没有连接,1表示为存在连接。 2. 接下来,可以使用DrawMap函数来绘制出环境地图。 3. 使用G2D函数将环境地图转换为邻接矩阵W。对于没有连接的节点,将其距离设置为无穷大。 4. 可以使用OPW函数对邻接矩阵进行优化处理,以便更好地表示节点之间的连接情况。 5. 使用dijkstra函数,设置起始栅格和目标栅格,并得到最路径距离以及栅格路径。 6. 使用Get_xy函数,将栅格路径转换为相应的x,y坐标。 7. 最后,使用Plot函数将最路径在环境地图上画出。 这样,就可以在MATLAB中实现Djkstra算法,并得到相应的最路径结果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【路径规划】基于matlab蚁群算法机器人栅格地图最路径规划【含Matlab源码 1618期】](https://blog.csdn.net/TIQCmatlab/article/details/122028266)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [【路径规划】基于matlab遗传算法机器人栅格地图最路径规划【含Matlab源码 175期】](https://blog.csdn.net/TIQCmatlab/article/details/122210837)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值