算法设计与分析实验:最短路径算法

一、网络延迟时间

力扣第743题

本题采用最短路径的思想进行求解

1.1 具体思路

(1)使用邻接表表示有向图:首先,我们可以使用邻接表来表示有向图。邻接表是一种数据结构,用于表示图中顶点的相邻关系。在这个问题中,我们可以使用字典(Python 中的 defaultdict)来实现邻接表,其中键是源节点,值是一个列表,包含了从该源节点出发的边以及对应的传递时间。

(2)使用最短路径算法计算从节点 K 到其他节点的最短路径:我们可以使用 Dijkstra 算法或者 Bellman-Ford 算法来计算从节点 K 到其他所有节点的最短路径。这些算法可以帮助我们找到从节点 K 出发,到达其他节点的最短路径长度。在这个问题中,我们可以使用 Dijkstra 算法,它能够高效地处理正权重边的最短路径问题。

(3)找出最长的最短路径:最后,我们找出所有最短路径中的最大值,即找到信号传递到所有节点所需的时间。这是因为信号需要经过最长的最短路径才能传递到所有节点。如果有节点无法收到信号,我们将返回-1。

1.2 思路展示

假设我们有以下有向图和起始节点 K:

图示例:

起始节点 K = 2

对应的邻接表为:

{

  2: [(1, 2), (3, 1)],

  3: [(4, 1)],

  1: [(3, 1), (4, 2)]

}

然后使用 Dijkstra 算法来计算从节点 2 出发到其他节点的最短路径。过程如下:

从节点 2 出发,到达节点 1 的距离为 2,到达节点 3 的距离为 1。

选择距离最短的节点 3,然后更新节点 3 相邻节点的距离:到达节点 4 的距离为 2。

最终得到的最短路径为:从节点 2 出发到节点 1 的最短路径长度为 2,到节点 3 的最短路径长度为 1,到节点 4 的最短路径长度为 2。

最长的最短路径为 2,即信号传递到所有节点所需的时间为 2。

1.3 代码实现

  1. import collections
    import heapqdef networkDelayTime(times, n, k):# 构建邻接表表示的有向图graph = collections.defaultdict(list)for u, v, w in times:graph[u].append((v, w))# 使用 Dijkstra 算法计算最短路径pq = [(0, k)]  # 优先队列,存储节点及当前距离dist = {}      # 存储从节点 K 到各节点的最短路径长度while pq:d, node = heapq.heappop(pq)if node in dist:continuedist[node] = dfor nei, d2 in graph[node]:if nei not in dist:heapq.heappush(pq, (d + d2, nei))# 找出最长的最短路径,即找到信号传递到所有节点所需的时间if len(dist) == n:return max(dist.values())else:return -1# 示例输入
    times = [[2, 1, 1], [2, 3, 1], [3, 4, 1]]
    n = 4
    k = 2# 输出结果
    print(networkDelayTime(times, n, k))

    1.4 复杂度分析

这段代码使用了Dijkstra算法来计算最短路径,下面是对其时间复杂度的分析:

构建邻接表表示的有向图:遍历times列表中的每个元素,时间复杂度为O(E),其中E为times的长度。

使用Dijkstra算法计算最短路径:最坏情况下,需要遍历所有的节点和边。每次从优先队列中弹出距离最小的节点,时间复杂度为O(logN),其中N为节点的总数。在每个节点上,需要遍历其邻居节点,时间复杂度为O(K),其中K为节点的平均邻居节点数。因此,总的时间复杂度为O((N+K)logN)。

找出最长的最短路径:遍历dist字典中的所有值,时间复杂度为O(N)。

综上所述,整体的时间复杂度为O(E + (N+K)logN + N)。空间复杂度为O(N+E),其中N为节点的总数,E为边的总数。

1.5 运行结果

# 示例输入

times = [[2, 1, 1], [2, 3, 1], [3, 4, 1]]

n = 4

k = 2

运行结果与预期一致

二、概率最大的路径

力扣第1514题

本题依旧采用最短路径的思想解决

2.1 具体思路

可以使用Dijkstra算法来解决。

首先构建无向加权图:使用字典graph来表示图,键为节点编号,值为一个列表,表示与该节点相邻的节点及对应的边权重。遍历edges和succProb两个列表,将节点和对应的边权重添加到graph中。

初始化距离列表和概率列表:使用列表dist和probs来分别存储从起点到每个节点的最短距离和成功概率。将起点的最短距离设置为1,其余节点的最短距离设置为0,起点的成功概率设置为1,其余节点的成功概率设置为0。

使用Dijkstra算法计算最短路径:使用堆优化的Dijkstra算法来计算从起点到每个节点的最短距离和成功概率。首先将起点加入优先队列pq。在每次循环中,从优先队列中弹出距离最小的节点node,遍历与该节点相邻的节点nei。如果从起点到nei的路径的成功概率乘以nei到node的边权重大于从起点到node的最短距离,并且这个概率乘以边权重大于nei节点当前的成功概率,则更新nei节点的最短距离和成功概率,并将(nei, -距离)添加到优先队列中。

返回终点的成功概率:如果终点的成功概率大于0,则返回终点的成功概率,否则返回0。

2.2 思路展示

假设给定无向加权图,其中节点0到节点3的成功概率最大。

首先,我们将这个图构建成一个字典graph,如下所示:

graph = {

    0: [(1, -math.log(0.5)), (2, -math.log(0.2))],

    1: [(0, -math.log(0.5)), (2, -math.log(0.5))],

    2: [(0, -math.log(0.2)), (1, -math.log(0.5)), (3, -math.log(0.3))],

    3: [(2, -math.log(0.3))]

}

接下来,我们初始化距离和概率列表,如下所示:

dist = [0, 0, 0, 0]

probs = [0, 0, 0, 0]

dist[0] = 1

probs[0] = 1

然后,我们使用Dijkstra算法计算最短路径。首先将起点0加入优先队列pq。在第一次循环中,从优先队列中弹出距离最小的节点0,遍历与该节点相邻的节点1和2。由于从起点到节点1的路径的成功概率乘以1到0的边权重(即-log(0.5))等于0.5,大于从起点到节点0的最短距离1,并且这个概率乘以边权重大于节点1当前的成功概率0,则更新节点1的最短距离和成功概率,并将(1, -距离)添加到优先队列中。同样的,我们也会更新节点2的最短距离和成功概率。

在第二次循环中,从优先队列中弹出距离最小的节点1,遍历与该节点相邻的节点0和2。由于从起点到节点0的路径的成功概率乘以1到0的边权重等于0.5,大于从起点到节点1的最短距离并且这个概率乘以边权重大于节点0当前的成功概率0,则更新节点0的最短距离和成功概率,并将(0, -距离)添加到优先队列中。同时,我们也会更新节点2的最短距离和成功概率。

在第三次循环中,从优先队列中弹出距离最小的节点2,遍历与该节点相邻的节点0、1和3。由于从起点到节点3的路径的成功概率乘以2到3的边权重(即-log(0.3))等于0.8,大于从起点到节点2的最短距离并且这个概率乘以边权重大于节点3当前的成功概率0,则更新节点3的最短距离和成功概率,并将(3, -距离)添加到优先队列中。我们也会更新节点0和1的最短距离和成功概率。

在最后一次循环中,从优先队列中弹出距离最小的节点3,发现它没有相邻的节点,结束Dijkstra算法的计算过程。

最后,我们返回终点3的成功概率0.25。

2.3 代码实现

import heapq
import math
from collections import defaultdictdef maxProbability(n, edges, succProb, start, end):# 构建无向带权图graph = defaultdict(list)for i in range(len(edges)):u, v = edges[i]p = succProb[i]graph[u].append((v, -math.log(p)))graph[v].append((u, -math.log(p)))# 初始化概率列表probs = [0] * nprobs[start] = 1# 使用Dijkstra算法计算最大成功概率路径pq = [(-1, start)]while pq:prob, node = heapq.heappop(pq)prob = -prob  # 取相反数以便按概率从大到小排序if node == end:return probfor nei, edge_prob in graph[node]:new_prob = prob * math.exp(edge_prob)if new_prob > probs[nei]:probs[nei] = new_probheapq.heappush(pq, (-new_prob, nei))# 如果没有从起点到终点的路径,则返回0return 0# 示例测试
n = 3
edges = [[0,1],[1,2],[0,2]]
succProb = [0.5,0.5,0.2]
start = 0
end = 2
print(maxProbability(n, edges, succProb, start, end))  # 输出: 0.25succProb = [0.5,0.5,0.3]
print(maxProbability(n, edges, succProb, start, end))  # 输出: 0.3edges = [[0,1]]
succProb = [0.5]
print(maxProbability(n, edges, succProb, start, end))  # 输出: 0

2.4 复杂度分析

这段代码的时间复杂度为 O(ElogV),其中 E 是边数,V 是节点数。这是因为在 Dijkstra 算法中,每条边最多会被遍历一次,而堆的插入和弹出操作的时间复杂度为 O(logV),因此总时间复杂度为 O(ElogV)。

空间复杂度为 O(V),主要是用来存储概率列表和堆。

2.5 运行结果

与预期结果均保持一致

三、最小路径和

力扣第64题

本题采用动态规划的思想解决

3.1 具体思路

定义一个二维数组 dp,其大小为 m x n。其中 dp[i][j] 表示从左上角到达网格位置 (i, j) 的最小路径和。

初始化第一行和第一列的路径和,因为只能向右或向下移动,所以第一行的路径和为前一个位置的路径和加上当前位置的值,第一列的路径和同理。

对于其他位置 (i, j),可以从上方或左方移动过来,选择路径和较小的那个路径,并加上当前位置的值。

遍历整个网格,更新 dp 数组中的路径和,直到达到右下角位置 (m-1, n-1)。

返回 dp[m-1][n-1],即右下角位置的最小路径和。

3.2 思路展示

假设输入的网格为:

1 3 1

1 5 1

4 2 1

首先定义一个二维数组 dp,其大小为 m x n。其中 dp[i][j] 表示从左上角到达网格位置 (i, j) 的最小路径和。

0 0 0

0 0 0

0 0 0

然后初始化第一行和第一列的路径和,因为只能向右或向下移动,所以第一行的路径和为前一个位置的路径和加上当前位置的值,第一列的路径和同理。

1 4 5

2 0 0

6 0 0

对于其他位置 (i, j),可以从上方或左方移动过来,选择路径和较小的那个路径,并加上当前位置的值。

1 4 5

2 7 6

6 8 7

遍历整个网格,更新 dp 数组中的路径和,直到达到右下角位置 (m-1, n-1)。

最后返回 dp[m-1][n-1],即右下角位置的最小路径和。

3.3 代码实现

def minPathSum(grid):m, n = len(grid), len(grid[0])dp = [[0] * n for _ in range(m)]# 初始化第一行和第一列的路径和dp[0][0] = grid[0][0]for i in range(1, m):dp[i][0] = dp[i-1][0] + grid[i][0]for j in range(1, n):dp[0][j] = dp[0][j-1] + grid[0][j]# 动态规划更新路径和for i in range(1, m):for j in range(1, n):dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]return dp[m-1][n-1]# 示例测试
grid = [[1,3,1],[1,5,1],[4,2,1]]
print(minPathSum(grid))  # 输出: 7grid = [[1,2,3],[4,5,6]]
print(minPathSum(grid))  # 输出: 12

3.4 复杂度分析

这段代码的时间复杂度为 O(m*n),其中 m 和 n 分别是网格的行数和列数。这是因为代码中使用了两层嵌套的循环来遍历整个网格,并更新 dp 数组中的路径和。

空间复杂度为 O(m*n),因为创建了一个与网格大小相同的二维数组 dp,用于存储路径和。

总结起来,这段代码通过动态规划的思想,利用一个二维数组记录从左上角到达每个位置的最小路径和,最后返回右下角位置的路径和。时间和空间复杂度都是网格的大小,因此在实践中,如果网格较大,可能需要考虑优化算法或使用其他方法来减少时间和空间开销。

3.5 运行结果

# 示例测试

grid = [[1,3,1],[1,5,1],[4,2,1]]

print(minPathSum(grid))  # 输出: 7

grid = [[1,2,3],[4,5,6]]

print(minPathSum(grid))  # 输出: 12

运行结果均与预期一致

结尾语

选择大于努力!

2025-2-2

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

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

相关文章

轻松打造智能化性能测试监控平台:【JMeter+Grafana+Influxdb】的优化整合方案

在当前激烈的市场竞争中,创新和效率成为企业发展的核心要素之一。在这种背景下,如何保证产品和服务的稳定性、可靠性以及高效性就显得尤为重要。 而在软件开发过程中,性能测试是一项不可或缺的环节,它可以有效的评估一个系统、应…

C语言·贪吃蛇游戏(下)

上节我们将要完成贪吃蛇游戏所需的前置知识都学完了,那么这节我们就开始动手写代码了 1. 程序规划 首先我们应该规划好我们的代码文件,设置3个文件:snack.h 用来声明游戏中实现各种功能的函数,snack.c 用来实现函数,t…

探索Web3.0:下一代互联网的新篇章

随着技术的不断演进和社会的持续发展,我们正逐渐迈入Web3.0时代。Web3.0,作为下一代互联网的代名词,不仅仅是技术的进步,更是一种全新的数字化生态系统,其所带来的影响将深刻地改变着我们的生活、工作和交流方式。 什…

Java二维码图片识别

前言 后端识别二维码图片 代码 引入依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.2.1</version></dependency><dependency><groupId>com.google.zxing<…

tuya-open-sdk-for-device使用体验之Windows 下 MSYS2 编译 T2-U 开发板

tuya-open-sdk-for-device 是一款跨芯片平台、操作系统的 IoT 开发框架。它基于通用南向接口设计&#xff0c;支持 Bluetooth、Wi-Fi、Ethernet 等通信协议&#xff0c;提供了物联网开发的核心功能&#xff0c;包括配网&#xff0c;激活&#xff0c;控制&#xff0c;升级等&…

2024美赛A题完整思路代码分析:建立竞争机理方程+遗传算法优化

A题是自由度比较大的场景限定下的模型构建&#xff0c;相对比较容易&#xff0c;核心是找到现有的成熟的数学模型&#xff0c;然后找到合适的数据进行证明得到结论&#xff0c;估计大部分是目标优化问题。&#xff08;不限制专业&#xff09; B题属于较为经典的物理建模&#…

【竞技宝】LOL:Able小炮连续起跳收割战场 OMG2-0轻取TT

北京时间2024年2月2日&#xff0c;英雄联盟LPL2024春季赛在昨天迎来第二周第四个比赛日&#xff0c;本日首场比赛由TT对阵OMG。本场比赛&#xff0c;TT在前中期和OMG有来有回&#xff0c;然而中后期的大龙团战始终不是OMG的对手&#xff0c;最终OMG2-0轻取TT。以下是本场比赛的…

linux vim 异常退出 异常处理 交换文件

交换文件 *.swp 格式 同时是隐藏的 如在vim一个文件&#xff0c; 在没有正常退出&#xff0c; 如直接断开连接 在次编辑这个文件 会出现下图的错误 解决方案&#xff1a; 直接删除这个交换文件即可 rm -fr .zen.txt.swp

唐墓惊现石椁,文物预防性保护系统未雨绸缪

一、文物保护的急需解决和科技的支持 陕西省考古学会近日宣布&#xff0c;考古团队在西安揭开了唐睿宗李旦孙媳妇薛柔顺墓的神秘面纱&#xff0c;其中出土的一具完整石椁&#xff0c;雕刻精湛、线条流畅&#xff0c;实属罕见珍宝。唐代石椁本就稀少&#xff0c;此次发现更是为…

RK3588开发板Ubuntu与开发板使用U盘互传

1 将 U 盘(U 盘的格式必须为 FAT32 格式&#xff0c;大小在 32G 以下)插到开发板的 usb 接口&#xff0c;串口打印信息如下所示&#xff0c;U 盘的设备节点是/dev/sdb4。U 盘的设备节点不是固定的&#xff0c;根据实际情况来查看设备节点。 2 输入以下命令挂载 U 盘&#xff0c…

Leetcode—2670. 找出不同元素数目差数组【简单】

2024每日刷题&#xff08;一零七&#xff09; Leetcode—2670. 找出不同元素数目差数组 哈希表实现代码 class Solution { public:vector<int> distinctDifferenceArray(vector<int>& nums) {unordered_set<int> s;int n nums.size();vector<int&g…

Qwen-VL 技术报告总结

感谢如此优秀的开源工作,仓库链接 Qwen-VL 权重分为 Qwen-VL && Qwen-VL-Chat,区别文档稍后介绍 训练过程 在第一阶段中主要使用224X224分辨率训练,训练数据主要来源是公开数据集,经过清洗,数据总量大约是1.4B,中文数据和英文j训练目标是视觉语言和文本语言对齐。…

docker集成 nacos/nacos-server (包括踩的坑)

tips 这边需要的数据库我已经安装好了&#xff0c;所以数据库的安装这边已经省略了 拉取镜像&#xff08;这边使用nacos1.4.1作为例子&#xff09; docker pull nacos/nacos-server:1.4.1创建映射的文件夹 (conf存放配置文件&#xff0c;logs存放日志文件) mkdir -p /data/n…

MySQL索引的原理和SQL优化策略

1. 索引 在InnoDB存储引擎中&#xff0c;索引分为聚簇索引和辅助索引两种类型。 聚簇索引是指基于表的主键构建的索引&#xff0c;它决定了表中数据的物理存储顺序。也就是说&#xff0c;聚簇索引中的键值按照主键的顺序来排序&#xff0c;并且每个叶子节点存储的是整个表行的…

HAL库配置PWM模式

一、什么是PWM 脉冲宽度调制(PWM)&#xff0c;是英文“Pulse Width Modulation”的缩写&#xff0c;简称脉宽调制。通过控制高低电平在一个周期内的占比从而输出一定的电压。 向上计数原理介绍 ​PWM的一个周期 定时器从0开始向上计数 当0-t1段,定时器计数器TIMx_CNT值小于…

直播团队职责

一、内容策划 直播团队的内容策划人员是整个直播活动的核心&#xff0c;他们需要负责策划直播的主题、内容、形式以及时间安排等。同时&#xff0c;他们还需要负责邀请嘉宾、安排活动等&#xff0c;确保直播内容丰富、有趣、有价值。 二、主播管理 主播是直播活动的关键人物…

unity WebGL发布游戏生成WebGL

1.unty Hub中安装WEBGL支持 2.项目平台的切换 color space需要根据项目选择 ColorSpace&#xff0c;是指玩家设置的颜色空间。 伽马颜色空间是历史悠久的标准格式&#xff0c;但线性颜色空间渲染可提供更精确的结果。 具体区别&#xff1a;ColorSpace 3.由于没有自己服务器…

壹[1],Xamarin开发环境配置

1&#xff0c;环境 VS2022 注&#xff1a; 1&#xff0c;本来计划使用AndroidStudio&#xff0c;但是也是一堆莫名的配置让人搞得很神伤&#xff0c;还是回归C#。 2&#xff0c;MAUI操作类似&#xff0c;但是很多错误解来解去&#xff0c;且调试起来很卡。 3&#xff0c;最…

如果你也觉得自己不够聪明,也缺乏才华。。。

​在追求成功的道路上&#xff0c;我们常常自我怀疑&#xff0c;感觉自己不够聪明&#xff0c;缺乏必要的才华。然而&#xff0c;正是这种自我感知&#xff0c;如果处理得当&#xff0c;可以成为我们最大的优势。这篇文章旨在为那些怀疑自己的能力&#xff0c;但依然渴望在工作…

图片热区功能

一、需求描述及效果图 1.需求描述&#xff1a; 根据后端返回的坐标及人员信息&#xff0c;在图片上的相应位置添加图片热区功能&#xff0c;点击可展示出对应的人员信息。 图片可进行缩放 2.示例&#xff1a; &#xff08;定位是随便写的&#xff0c;仅做示例&#xff09; …