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

news2024/10/6 8:35:10

一、网络延迟时间

力扣第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 heapq
    
    def 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:
                continue
            dist[node] = d
            for 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 defaultdict

def 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] * n
    probs[start] = 1

    # 使用Dijkstra算法计算最大成功概率路径
    pq = [(-1, start)]
    while pq:
        prob, node = heapq.heappop(pq)
        prob = -prob  # 取相反数以便按概率从大到小排序
        if node == end:
            return prob
        for nei, edge_prob in graph[node]:
            new_prob = prob * math.exp(edge_prob)
            if new_prob > probs[nei]:
                probs[nei] = new_prob
                heapq.heappush(pq, (-new_prob, nei))

    # 如果没有从起点到终点的路径,则返回0
    return 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.25

succProb = [0.5,0.5,0.3]
print(maxProbability(n, edges, succProb, start, end))  # 输出: 0.3

edges = [[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))  # 输出: 7

grid = [[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.coloradmin.cn/o/1428326.html

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

相关文章

【C语言进阶篇】assert宏 使用详解

文章目录 一、assert简介 二、assert使用方法和规则 2.1 头文件 2.2 原型 2.3 功能 2.4 示例 2.5 assert的打开与关闭 三、注意事项 3.1 运行效率问题 3.2 assert只适用于调试版本 3.3 资源释放与清理 3.4 过度依赖 四、总结 个人主页: 倔强的石头的…

Datax3.0+DataX-Web部署分布式可视化ETL系统

一、DataX 简介 DataX 是阿里云 DataWorks 数据集成的开源版本,主要就是用于实现数据间的离线同步。DataX 致力于实现包括关系型数据库(MySQL、Oracle 等)、HDFS、Hive、ODPS、HBase、FTP 等各种异构数据源(即不同的数据库&#x…

(2024,SaFaRI,双三上采样和 DFT,空间特征和频率特征)基于扩散模型的图像空间和频率感知恢复方法

Spatial-and-Frequency-aware Restoration method for Images based on Diffusion Models 公和众和号:EDPJ(进 Q 交流群:922230617 或加 VX:CV_EDPJ 进 V 交流群) 目录 0. 摘要 3. 方法 3.1 修改数据保真度 3.2 …

Python中使用Opencv-python库绘制直线、矩形、圆、文本

Python中使用Opencv-python库绘制直线、矩形、圆、文字 在Python中使用Opencv-python绘制直线、矩形、圆、文本非常简单,分别使用到line、rectangle、circle、putText这几个函数,具体可以参考https://docs.opencv.org/4.9.0/d6/d6e/group__imgproc__dra…

基础小白快速入门c语言----数据类型

数据类型,运算符,表达式 1c语言支持 数据类型 1.基础类型(基本类型) a数值类型 整型:往往有符号和无符号的区分,(signed)有符号 (unsigned)无符号 基础整型&#xff1…

GSM模块的使用及注意事项

1.如何使用? 最近,我准备使用GSM模块(SIM900A)发送英文短信到指定号码,翻阅资料如下: 可见,只要给该模块按照如下步骤发送指令: 就可以使得模块正常工作。(SIM900A&#…

6-1 A. DS二叉树—二叉树构建与遍历(不含框架)

题目描述 给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符‘#’表示,例如AB#C##D##),建立该二叉树的二叉链式存储结构,并输出该二叉树的先序遍历、中序遍历和后序遍历结果。 输入 第…

【Java程序设计】【C00231】基于Springboot的景区寄存管理系统(有论文)

基于Springboot的景区寄存管理系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的景区行李寄存系统 主要功能如下:用户登录模块、用户信息管理模块、角色信息管理模块、部门信息管理模块、行李寄存柜…

十、Qt三维图表

一、Data Visualization模块概述 Data Visualization的三维显示功能主要有三种三维图形来实现,三各类的父类都是QAbstract3DGraph,从QWindow继承而来。这三类分别是:三维柱状图Q3DBar三维空间散点Q3DScatter三维曲面Q3DSurface 1、相关类的…

窥探向量乘矩阵的存内计算原理—基于向量乘矩阵的存内计算

在当今计算领域中,存内计算技术凭借其出色的向量乘矩阵操作效能引起了广泛关注。本文将深入研究基于向量乘矩阵的存内计算原理,并探讨几个引人注目的代表性工作,如DPE、ISAAC、PRIME等,它们在神经网络和图计算应用中表现出色&…

【笔记】Android 常用编译模块和输出产物路径

模块&产物路径 具体编译到软件的路径要看编译规则的分区,代码中模块编译输出的产物基本对应。 Android 代码模块 编译产物路径设备adb路径Comment 模块device/mediatek/system/common/ 资源overlay/telephony/frameworks/base/core 文件举例res/res/values-m…

Java项目:基于SSM框架实现的教务管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm813基于SSM框架实现的教务管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#x…

增加Vscode引用路径

增加Vscode引用路径 增加Vscode引用路径问题说明解决思路1在Vscode中进行配置缺点 解决思路2 增加Vscode引用路径 问题说明 在嵌入式开发中需要经常用到库函数(SPL), Vscode需要配置引用路径才能对函数名或变量进行跳转 解决思路1 与Keil5 MDK类似, 在配置C/C的json文件中添…

论在线测径仪在胶管生产行业的投资与回报!

关键词:在线测径仪,胶管测径仪,双轴测径仪,双向测径仪,测径仪,胶管外径检测 胶管种类多、应用广,在胶管生产行业中,在不断加深其自动化程度,在加深的过程中,先要考虑到的是其投入产出比,是否值得投入。在胶…

【自动化测试】---Selenium+Java

1.自动化测试分类 接口自动化测试UI自动化测试(移动端自动化测试、Web端自动化测试) 2.选择Selenium作为web自动化工具原因(面试题) 开源免费支持多个浏览器支持多个系统支持多语言Selenium包提供很多供测试使用的API 3.自动化是什…

从零开始学Linux之gcc链接

目录 创建静态库并使用 创建动态库(共享库)并使用 链接:将.o目标文件链接起来生成一个可执行程序文件,可分为静态链接和动态链接 静态链接:链接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整…

echarts step line

https://ppchart.com/#/ <template><div class"c-box" ref"jsEchart"></div> </template><script> import * as $echarts from echarts // 事件处理函数 export default {props: {// 需要传递的数据data: {type: Array,defa…

单臂路由实验(思科)

一&#xff0c;实验目的 在路由器的一个接口上通过配置子接口的方式&#xff0c;实现相互隔离的不同vlan之间互通。 二&#xff0c;设备配置 Switch1 Switch>enable 全局模式 Switch#configure terminal 配置模式 Switch(config)#vlan 10 …

【文件上传WAF绕过】<?绕过、.htaccess木马、.php绕过

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

蓝桥杯-常用STL(二)

常用STL &#x1f388;1.集合&#x1f388;2.set的基础使用&#x1f52d;2.1引入库&#x1f52d;2.2插入元素&#x1f52d;2.3删除元素&#x1f52d;2.4判断元素是否存在&#x1f52d;2.5遍历元素&#x1f52d;2.6清空 &#x1f388;3.set与结构体 &#x1f388;1.集合 &#x…