Dijkstra算法解析

Dijkstra算法,用于求解图中从一个起点到其他所有节点的最短路径。解决单源最短路径问题的有效方法。

条件

有向

带权路径

时间复杂度 O(n平方)

方法步骤

1 把图上的点分为两个集合 要求的起点 和除了起点之外的点 。能直达的写上权值 不能直达的写上无穷 自己到自己的距离是0

2 在除起点以外的中找权值最小的顶点,这个顶点加入起点所在的集合。由于新顶点的并入,可以把新顶点作为中转点,再重新计算起点到所有除已经并入顶点的距离,找最小的继续并入,直到所有顶点并入起点所在的集合。

以下是对代码的详细解析和注释:

代码解析

全局变量定义
#define N 1005 // 定义最大顶点数为1005
int n, m; // n表示顶点数,m表示边数
bool str[N]; // 用于标记是否已确定最短路径
int dis[N]; // 存储从起始点到各个顶点的最短距离
int g[N][N]; // 邻接矩阵,存储图的结构
  • N:定义图中最大顶点数为1005。

  • nm:分别表示图中的顶点数和边数。

  • str:布尔数组,用于标记某个顶点是否已经确定了最短路径。

  • dis:数组,存储从起点到每个顶点的最短距离。

  • g:邻接矩阵,g[i][j] 表示从顶点 i 到顶点 j 的距离。

Dijkstra算法实现
void dijkstra() {// 初始化dis数组为一个很大的值(这里选择0x3f3f3f3f)memset(dis, 0x3f3f3f3f, sizeof(dis));// 起始点到自身的距离为0dis[1] = 0;for (int i = 1; i <= n; ++i) {int temp = -1; // 选择未确定的顶点// 寻找当前未确定的最小距离顶点for (int j = 1; j <= n; ++j)if (!str[j] && (temp == -1 || dis[j] < dis[temp]))temp = j;// 更新与该顶点相邻的其他顶点的距离for (int j = 1; j <= n; ++j)dis[j] = min(dis[j], dis[temp] + g[temp][j]);// 标记该顶点已经确定了最短路径str[temp] = true;}// 输出结果for (int i = 1; i <= n; ++i) {if (dis[i] == 0x3f3f3f3f)cout << "-1" << " "; // 如果没有到该顶点的路径则输出-1elsecout << dis[i] << " "; // 否则输出最短距离}
}
  1. 初始化

    • memset(dis, 0x3f3f3f3f, sizeof(dis));:将 dis 数组初始化为一个很大的值(0x3f3f3f3f),表示初始时从起点到其他顶点的距离是无穷大。

    • dis[1] = 0;:将起点到自身的距离设置为0。

  2. 主循环

    • for (int i = 1; i <= n; ++i):循环 n 次,每次找到一个未确定最短路径的顶点。

    • int temp = -1;:初始化当前未确定的最短距离顶点为 -1。

    • for (int j = 1; j <= n; ++j):遍历所有顶点,找到未确定最短路径的顶点中距离最短的顶点 temp

      • if (!str[j] && (temp == -1 || dis[j] < dis[temp])):如果顶点 j 未确定最短路径且距离更短,则更新 temp

    • for (int j = 1; j <= n; ++j):更新与顶点 temp 相邻的其他顶点的距离。

      • dis[j] = min(dis[j], dis[temp] + g[temp][j]);:如果通过 temp 到达 j 的距离更短,则更新 dis[j]

    • str[temp] = true;:标记顶点 temp 已经确定了最短路径。

  3. 结果输出

    • 遍历 dis 数组,输出从起点到每个顶点的最短距离。

    • 如果 dis[i] 仍然是 0x3f3f3f3f,表示没有路径到达顶点 i,输出 -1

    • 否则输出 dis[i]

主函数
int main() {// 初始化邻接矩阵g为一个很大的值memset(g, 0x3f3f3f3f, sizeof(g));// 输入顶点数n和边数mcin >> n >> m;while (m--) { // 处理每一条边的输入int x, y, z;cin >> x >> y >> z;// 更新邻接矩阵g中的权值g[x][y] = min(g[x][y], z);}// 调用dijkstra函数求解dijkstra();return 0;
}
  1. 初始化邻接矩阵

    • memset(g, 0x3f3f3f3f, sizeof(g));:将邻接矩阵 g 初始化为一个很大的值(0x3f3f3f3f),表示初始时图中没有边。

  2. 输入图的边

    • cin >> n >> m;:读取顶点数 n 和边数 m

    • while (m--):循环 m 次,读取每一条边的信息。

      • cin >> x >> y >> z;:读取边的起点 x、终点 y 和权重 z

      • g[x][y] = min(g[x][y], z);:更新邻接矩阵 g 中的权值,如果有多条边连接同一对顶点,只保留权重最小的那条边。

  3. 调用Dijkstra算法

    • dijkstra();:调用 dijkstra 函数求解最短路径。

  4. 输出结果

    • dijkstra 函数会输出从起点到每个顶点的最短距离。

示例输入和输出

示例输入
5 7
1 2 4
1 3 3
2 4 2
3 2 1
3 4 5
4 5 1
2 5 7
示例输出

0 2 3 4 5

解释
  • 顶点 1 到顶点 2 的最短距离为 2(1 -> 3 -> 2)。

  • 顶点 1 到顶点 3 的最短距离为 3(1 -> 3)。

  • 顶点 1 到顶点 4 的最短距离为 4(1 -> 3 -> 2 -> 4)。

  • 顶点 1 到顶点 5 的最短距离为 5(1 -> 3 -> 2 -> 4 -> 5)。

关键点总结

  1. 邻接矩阵:使用二维数组 g[N][N] 表示图的结构,g[i][j] 表示从顶点 i 到顶点 j 的距离。

  2. 选择最短距离顶点:通过遍历所有顶点,找到未确定最短路径的顶点中距离最短的顶点。

  3. 更新邻接顶点的距离:通过当前顶点更新其邻接顶点的距离。

  4. 标记顶点:使用布尔数组 str 标记顶点是否已经确定了最短路径。

Dijkstra算法详细步骤解析

1. 初始化

在算法开始之前,需要进行以下初始化操作:

  1. 初始化距离数组 dis

    • dis 数组中的所有元素初始化为一个很大的值(如 0x3f3f3f3f),表示从起点到其他顶点的距离初始为无穷大。

    • 将起点的距离设置为 0,即 dis[start] = 0

  2. 初始化访问标记数组 str

    • str 数组中的所有元素初始化为 false,表示所有顶点初始时都未被访问过。

  3. 初始化邻接矩阵 g

    • 将邻接矩阵 g 中的所有元素初始化为一个很大的值(如 0x3f3f3f3f),表示初始时图中没有边。

2. 主循环

Dijkstra算法的核心是一个主循环,该循环执行 n 次(n 为顶点数),每次找到一个未访问的最短距离顶点,并更新其邻接顶点的距离。

  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u

    • 如果所有顶点都已被访问过,或者没有找到未访问的顶点,则退出循环。

  2. 更新邻接顶点的距离

    • 遍历顶点 u 的所有邻接顶点 v,如果通过 u 到达 v 的距离更短,则更新 dis[v]

    • 具体来说,如果 dis[u] + g[u][v] < dis[v],则更新 dis[v] = dis[u] + g[u][v]

  3. 标记顶点为已访问

    • 将顶点 u 标记为已访问,即 str[u] = true,避免重复处理。

3. 结果输出

在主循环结束后,dis 数组中存储了从起点到每个顶点的最短距离。遍历 dis 数组,输出结果:

  • 如果 dis[i] 仍然是初始的大值(如 0x3f3f3f3f),表示没有路径到达顶点 i,输出 -1

  • 否则,输出 dis[i],表示从起点到顶点 i 的最短距离。

示例执行过程

假设图的结构如下:

  • 顶点数 n = 5

  • 边数 m = 7

  • 边的权重如下:

    • 1 -> 2: 4

    • 1 -> 3: 3

    • 2 -> 4: 2

    • 3 -> 2: 1

    • 3 -> 4: 5

    • 4 -> 5: 1

    • 2 -> 5: 7

初始化
  • dis 数组:[0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f]

  • str 数组:[false, false, false, false, false]

  • g 邻接矩阵:

    [[0x3f3f3f3f, 4, 3, 0x3f3f3f3f, 0x3f3f3f3f],[0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 2, 0x3f3f3f3f],[0x3f3f3f3f, 1, 0x3f3f3f3f, 5, 0x3f3f3f3f],[0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 1],[0x3f3f3f3f, 7, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f]
    ]
第1次循环
  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u = 1(起点)。

  2. 更新邻接顶点的距离

    • 遍历顶点 1 的邻接顶点 23

      • dis[2] = min(dis[2], dis[1] + g[1][2]) = min(0x3f3f3f3f, 0 + 4) = 4

      • dis[3] = min(dis[3], dis[1] + g[1][3]) = min(0x3f3f3f3f, 0 + 3) = 3

  3. 标记顶点为已访问

    • str[1] = true

第2次循环
  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u = 3dis[3] = 3)。

  2. 更新邻接顶点的距离

    • 遍历顶点 3 的邻接顶点 24

      • dis[2] = min(dis[2], dis[3] + g[3][2]) = min(4, 3 + 1) = 4

      • dis[4] = min(dis[4], dis[3] + g[3][4]) = min(0x3f3f3f3f, 3 + 5) = 8

  3. 标记顶点为已访问

    • str[3] = true

第3次循环
  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u = 2dis[2] = 4)。

  2. 更新邻接顶点的距离

    • 遍历顶点 2 的邻接顶点 45

      • dis[4] = min(dis[4], dis[2] + g[2][4]) = min(8, 4 + 2) = 6

      • dis[5] = min(dis[5], dis[2] + g[2][5]) = min(0x3f3f3f3f, 4 + 7) = 11

  3. 标记顶点为已访问

    • str[2] = true

第4次循环
  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u = 4dis[4] = 6)。

  2. 更新邻接顶点的距离

    • 遍历顶点 4 的邻接顶点 5

      • dis[5] = min(dis[5], dis[4] + g[4][5]) = min(11, 6 + 1) = 7

  3. 标记顶点为已访问

    • str[4] = true

第5次循环
  1. 选择未访问的最短距离顶点

    • 遍历所有顶点,找到未访问的顶点中距离最短的顶点 u = 5dis[5] = 7)。

  2. 更新邻接顶点的距离

    • 顶点 5 没有邻接顶点,无需更新。

  3. 标记顶点为已访问

    • str[5] = true

结果输出

遍历 dis 数组,输出从起点到每个顶点的最短距离:

  • dis[1] = 0

  • dis[2] = 4

  • dis[3] = 3

  • dis[4] = 6

  • dis[5] = 7

关键点总结

  1. 选择未访问的最短距离顶点

    • 每次选择未访问的顶点中距离最短的顶点,确保每一步都选择当前最优的顶点进行处理。

  2. 更新邻接顶点的距离

    • 通过当前顶点更新其邻接顶点的距离,确保每一步都更新到最新的最短距离。

  3. 标记顶点为已访问

    • 避免重复处理已访问的顶点,提高算法的效率。

  4. 结果输出

    • 最终输出从起点到每个顶点的最短距离,如果没有路径到达某个顶点,则输出 -1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/11025.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes组成及常用命令

Pods(k8s最小操作单元)ReplicaSet & Label(k8s副本集和标签)Deployments(声明式配置)Services(服务)k8s常用命令Kubernetes(简称K8s)是一个开源的容器编排系统,用于自动化应用程序的部署、扩展和管理。自2014年发布以来,K8s迅速成为容器编排领域的行业标准,被…

hexo部署到github page时,hexo d后page里面绑定的个人域名消失的问题

Hexo 部署博客到 GitHub page 后&#xff0c;可以在 setting 中的 page 中绑定自己的域名&#xff0c;但是我发现更新博客后绑定的域名消失&#xff0c;恢复原始的 githubio 的域名。 后面搜索发现需要在 repo 里面添加 CNAME 文件&#xff0c;内容为 page 里面绑定的域名&…

vim的特殊模式-可视化模式

可视化模式&#xff1a;按 v进入可视化模式 选中 y复制 d剪切/删除 可视化块模式: ctrlv 选中 y复制 d剪切/删除 示例&#xff1a; &#xff08;vim可视化模式的进阶使用&#xff1a;vim可视化模式的进阶操作-CSDN博客&#xff09;

【教程】在CMT上注册账号并声明Conflicts

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 注册账号 声明冲突 账号验证 每位作者都要注册并声明冲突&#xff0c;不然会直接拒稿&#xff01; 注册账号 https://cmt3.research.microsoft…

拉格朗日定理

根号n为枚举的条件 d从c开始循环&#xff08;防止重复计算平方和&#xff09; #include<bits/stdc.h> using namespace std; using lllong long; const int N5e69;int n; int C[N],D[N];int main() {cin>>n;memset(C,-1,sizeof C);for(int c0;c*c<n;c)for(int d…

什么是线性化PDF?

线性化PDF是一种特殊的PDF文件组织方式。 总体而言&#xff0c;PDF是一种极为优雅且设计精良的格式。PDF由大量PDF对象构成&#xff0c;这些对象用于创建页面。相关信息存储在一棵二叉树中&#xff0c;该二叉树同时记录文件中每个对象的位置。因此&#xff0c;打开文件时只需加…

省级-新质生产力数据(2010-2022年)-社科数据

省级-新质生产力数据&#xff08;2010-2022年&#xff09;-社科数据https://download.csdn.net/download/paofuluolijiang/90028612 https://download.csdn.net/download/paofuluolijiang/90028612 新质生产力是指在现代科技和经济社会发展的推动下&#xff0c;由新的生产要素…

17.2 图形绘制6

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.2.7 Screen类 Screen类从字面上看就知道是与屏幕显示相关的&#xff0c;表示单个系统上的一个或多个显示设备。 Screen常用属性…

第一个Python程序

目录 1.命令行模式 2.Python交互模式 3.命令行模式和Python交互模式 4.SyntaxError 5.小结 2.使用文本编辑器 1.Visual Studio Code! 2.直接运行py文件 3.输入和输出 1.输出 2.输入 3.小结 在正式编写第一个Python程序前&#xff0c;我们先复习一下什么是命令行模式…

14-9-1C++STL的set容器

&#xff08;一&#xff09;set容器的基本概念 1. set是一个集合容器&#xff0c;其中所包含的元素是唯一的&#xff0c;集合中的元素按一定的顺序排列&#xff0c;元素插入过程是按排序规则插入&#xff0c;所以不能指定插入位置 2. set深用红黑树变体的数据结构实现&#xff…

数据分析系列--②RapidMiner导入数据和存储过程

一、下载数据 二、导入数据 1. 在本地计算机中创建3个文件夹 2. 从本地选择.csv或.xlsx 三、界面说明 四、存储过程 1.保存 Congratulations, you are done. 一、下载数据 点击下载AssociationAnalysisData.xlsx数据集 二、导入数据 1. 在本地计算机中创建3个文件夹 2. 从…

被裁与人生的意义--春节随想

还有两个月就要被迫离开工作了十多年的公司了&#xff0c;不过有幸安安稳稳的过了一个春节&#xff0c;很知足! 我是最后一批要离开的&#xff0c;一百多号同事都没“活到”蛇年。看着一批批仁人志士被“秋后斩首”&#xff0c;马上轮到我们十来个&#xff0c;个中滋味很难言清…

Docker自定义镜像

Dockerfile自定义镜像 一&#xff1a;镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 我们以MySQL为例&#xff0c;来看看镜像的组成结构&#xff1a; 简单来说&#xff0c;镜像就是在系统函数库、运行环境基础上&#xff0c;添加应用程序文件、…

论文阅读(十六):利用线性链条件随机场模型检测阵列比较基因组杂交数据的拷贝数变异

1.论文链接&#xff1a;Detection of Copy Number Variations from Array Comparative Genomic Hybridization Data Using Linear-chain Conditional Random Field Models 摘要&#xff1a; 拷贝数变异&#xff08;CNV&#xff09;约占人类基因组的12%。除了CNVs在癌症发展中的…

ASP.NET Core 中间件

目录 一、常见的内置中间件 二、自定义中间件 三、中间件的执行顺序 四、其他自动逸中间件案例 1. 身份验证中间件 2、跨域中间件&#xff08;CORS&#xff09; ASP.NET Core 中&#xff0c;中间件&#xff08;Middleware&#xff09;是处理 HTTP 请求和响应的组件链。你…

JavaScript中的数组方法总结+详解

在JS中,数组方法是非常重要且常用的方法.在此整理总结一番. 1. javaScript常用数组方法 2.方法详解 1.push(); 功能: 在数组最后一位添加一个或多个元素,并返回新数组的长度,改变原数组.(添加多个元素用逗号隔开) var arr [1, 2, "c"];var rel arr.push(&q…

「全网最细 + 实战源码案例」设计模式——桥接模式

核心思想 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;将抽象部分与其实现部分分离&#xff0c;使它们可以独立变化。降低代码耦合度&#xff0c;避免类爆炸&#xff0c;提高代码的可扩展性。 结构 1. Implementation&#xff08;实现类…

动态规划DP 背包问题 完全背包问题(题目分析+C++完整代码)

概览检索 动态规划DP 概览&#xff08;点击链接跳转&#xff09; 动态规划DP 背包问题 概览&#xff08;点击链接跳转&#xff09; 完全背包问题 原题链接 AcWiing 3. 完全背包问题 题目描述 有 N种物品和一个容量是 V的背包&#xff0c;每种物品都有无限件可用。 第 i种物…

开源智慧园区管理系统对比五款主流产品探索智能运营新模式

内容概要 在这个数字化迅速发展的时代&#xff0c;园区管理也迎来了全新的机遇和挑战。众所周知&#xff0c;开源智慧园区管理系统作为一种创新解决方案&#xff0c;正逐步打破传统管理的局限性。它的开放性不仅使得系统可以根据具体需求进行灵活调整&#xff0c;也为用户提供…

Unity实现按键设置功能代码

一、前言 最近在学习unity2D&#xff0c;想做一个横版过关游戏&#xff0c;需要按键设置功能&#xff0c;让用户可以自定义方向键与攻击键等。 自己写了一个&#xff0c;总结如下。 二、界面效果图 这个是一个csv文件&#xff0c;准备第一列是中文按键说明&#xff0c;第二列…