Dijkstra算法,动态规划和滑动窗口

一:最小花费

题目链接:1928. 规定时间内到达终点的最小花费 - 力扣(LeetCode)

(1)Dijkstra算法

  1. 理解问题:首先,我们需要理解问题的核心是找到一条从城市 0 到城市 n-1 的路径,这条路径在不超过给定时间 maxTime 的前提下,通行费之和最小。

  2. 图的表示:由于城市之间是通过双向道路连接的,我们可以将这个问题抽象为一个图问题,其中城市是节点,道路是边。边的权重是通行时间。

  3. 算法选择:由于我们需要找到最小费用的路径,这看起来像是一个最短路径问题。但是,这里的最短路径是在时间限制下的费用最小,所以我们需要一个能够同时考虑时间和费用的算法。Dijkstra算法是一个很好的选择,但我们需要对其进行修改以考虑时间限制。

  4. 优先队列的使用:为了高效地找到当前费用最小的路径,我们使用优先队列(最小堆)。这样我们可以始终从当前费用最小的路径开始扩展。

  5. 状态记录:由于我们可能多次经过同一个城市,但时间不同,我们需要记录每个城市在不同时间点的访问状态。这通过 visited 数组实现,它是一个二维数组,其中 visited[i][t] 表示在城市 i 在时间 t 是否已经访问过。

  6. 算法流程

    • 初始化:将起点城市 0 加入优先队列,费用为 passingFees[0],时间为 0。
    • 循环:从优先队列中取出当前费用最小的路径,检查是否到达终点城市。如果是,返回当前费用。
    • 扩展:对于当前城市的每个邻接城市,计算到达邻接城市的新时间和新费用。如果新时间不超过 maxTime 且该状态未被访问过,则将其加入优先队列,并标记为已访问。
  7. 结束条件:如果优先队列为空,说明在给定时间内无法到达终点城市,返回 -1。

  8. 返回结果:如果在循环中找到了到达终点城市的路径,返回该路径的费用。如果循环结束仍未找到,返回 -1。

import heapqdef minCost(maxTime, edges, passingFees):n = len(passingFees)graph = [[] for _ in range(n)]for u, v, time in edges:graph[u].append((v, time))graph[v].append((u, time))pq = [(passingFees[0], 0, 0)]visited = [False] * nmin_cost = [float('inf')] * nmin_cost[0] = passingFees[0]while pq:cost, u, time_used = heapq.heappop(pq)if visited[u]:continuevisited[u] = Trueif u == n - 1:return costfor v, time in graph[u]:new_time = time_used + timeif new_time <= maxTime and cost + passingFees[v] < min_cost[v]:min_cost[v] = cost + passingFees[v]heapq.heappush(pq, (min_cost[v], v, new_time))return -1# 解析输入
def parse_input(input_str):parts = input_str.split(', ')maxTime = int(parts[0].split(' = ')[1])edges_start = parts[1].find('[[')edges_end = parts[1].find(']]') + 2edges_str = parts[1][edges_start:edges_end]edges = eval(edges_str)passingFees_start = parts[2].find('[')passingFees = eval(parts[2][passingFees_start:])return maxTime, edges, passingFeesinput_str = input()
maxTime, edges, passingFees = parse_input(input_str)# 计算并输出结果
result = minCost(maxTime, edges, passingFees)
print(result)

(2)动态规划

  1. 定义状态:在这个问题中,我们定义 dp[i][t] 为到达城市 i 并且花费时间为 t 时的最小通行费总和。

  2. 状态初始化:由于我们一开始在城市 0,所以 dp[0][0] 初始化为 passingFees[0],即经过城市 0 的通行费。其他状态初始化为无穷大(float('inf')),表示在初始状态下无法到达。

  3. 状态转移:对于每个城市 i 和每个时间 t,我们需要考虑所有从城市 i 出发的边 (i, j, timeij)。如果从城市 i 到城市 j 需要的时间 timeij 加上当前时间 t 不超过 maxTime,并且新的费用 dp[i][t] + passingFees[j] 小于 dp[j][t + timeij],则更新 dp[j][t + timeij]

  4. 使用优先队列优化:由于我们希望在给定的时间内找到最小费用,可以使用优先队列(最小堆)来优化搜索过程。我们每次从优先队列中取出当前费用最小的状态,并尝试从这个状态转移到其他状态。

  5. 结果提取:在完成所有状态转移后,我们需要在 dp[n-1](即到达城市 n-1 的所有可能时间)中找到最小的费用。如果这个最小费用仍然是无穷大,则说明无法在 maxTime 时间内到达城市 n-1,返回 -1。

具体步骤如下:

  • 初始化 dp 表和优先队列。
  • 将起点(城市 0,费用 passingFees[0],时间 0)加入优先队列。
  • 当优先队列不为空时,取出当前费用最小的状态,并尝试从这个状态转移到其他状态。
  • 更新 dp 表和优先队列。
  • 最后在 dp[n-1] 中找到最小费用并返回。

这个动态规划的方法实际上是一个基于优先队列的 Dijkstra 算法的变种,用于在给定时间限制内找到最小费用的路径。

from collections import defaultdict
import heapqdef minCost(maxTime, edges, passingFees):n = len(passingFees)graph = defaultdict(list)for u, v, time in edges:graph[u].append((v, time))graph[v].append((u, time))dp = [[float('inf')] * (maxTime + 1) for _ in range(n)]dp[0][0] = passingFees[0]pq = [(passingFees[0], 0, 0)]  # (cost, node, time)while pq:cost, node, time = heapq.heappop(pq)if node == n - 1:return costfor neighbor, travel_time in graph[node]:new_time = time + travel_timenew_cost = cost + passingFees[neighbor]if new_time <= maxTime and new_cost < dp[neighbor][new_time]:dp[neighbor][new_time] = new_costheapq.heappush(pq, (new_cost, neighbor, new_time))min_cost = min(dp[n-1][:maxTime+1])return min_cost if min_cost != float('inf') else -1# 获取用户输入
points_input = input()
angle_input = int(input())
location_input = input()# 将输入字符串转换为相应的数据类型
points = eval(points_input)
angle = angle_input
location = eval(location_input)# 调用函数并打印结果
print(visible_points(points, angle, location))

二:可见点的最大数目

题目链接:1610. 可见点的最大数目 - 力扣(LeetCode)

滑动窗口

为了解决这个问题,我们可以采用以下步骤:

  1. 计算每个点相对于你的位置的角度。
  2. 将这些角度按照从小到大的顺序排序。
  3. 使用滑动窗口的方法来找到在给定角度范围内可以看到的最多点数。
import mathdef visible_points(points, angle, location):# 计算每个点相对于location的角度angles = []same_pos_count = 0for point in points:dx, dy = point[0] - location[0], point[1] - location[1]if dx == 0 and dy == 0:same_pos_count += 1continueangle = math.degrees(math.atan2(dy, dx))angles.append(angle)# 将角度排序angles.sort()# 将角度列表扩展,以处理跨越0度线的情况angles += [a + 360 for a in angles]# 使用滑动窗口找到最大的可见点数max_visible = 0left = 0for right in range(len(angles)):while angles[right] - angles[left] > angle:left += 1max_visible = max(max_visible, right - left + 1)return max_visible + same_pos_count# 获取用户输入
points_input = input()
angle_input = int(input()
location_input = input()# 将输入字符串转换为相应的数据类型
points = eval(points_input)
angle = angle_input
location = eval(location_input)# 调用函数并打印结果
print(visible_points(points, angle, location))

这段代码的目的是计算在给定的角度范围内,从特定位置出发可以看到的最大点数。以下是代码的思路和步骤:

  1. 初始化变量:

    • angles: 用于存储每个点相对于观察位置的角度。
    • same_pos_count: 用于计数与观察位置重合的点的数量。
  2. 计算每个点的角度:

    • 遍历点数组 points
    • 对于每个点,计算它与观察位置 location 在 x 和 y 轴上的差值 dx 和 dy
    • 如果一个点与观察位置重合(即 dx == 0 且 dy == 0),则增加 same_pos_count 并跳过后续计算。
    • 使用 math.atan2(dy, dx) 计算该点的角度(以弧度为单位),然后使用 math.degrees() 将其转换为度数。
    • 将计算出的角度添加到 angles 列表中。
  3. 处理角度列表:

    • 对 angles 列表进行排序,以便我们可以使用滑动窗口方法来找到给定角度范围内的最大点数。
    • 为了处理跨越0度线的情况(例如从350度到10度),将 angles 列表中的每个角度加上360度后追加到列表的末尾。这样,我们就可以在0度线周围无缝地滑动窗口。
  4. 滑动窗口查找最大可见点数:

    • 初始化 max_visible 为0,这是我们将要返回的最大可见点数。
    • 使用两个指针 left 和 right 来表示滑动窗口的左右边界。
    • 遍历 angles 列表,对于每个 right 指针的位置,检查窗口内的角度范围是否超过了给定的 angle
    • 如果超过了,移动 left 指针,缩小窗口范围,直到窗口内的角度范围小于或等于给定的 angle
    • 更新 max_visible 为当前窗口内点的数量和之前记录的最大数量的较大值。
  5. 返回结果:

    • 将 max_visible(滑动窗口中可见点的最大数量)与 same_pos_count(与观察位置重合的点的数量)相加,得到最终结果。
    • 返回这个值,它表示在给定角度范围内从观察位置可以看到的最大点数。

这段代码有效地处理了观察角度范围内点的可见性问题,并且能够处理包括观察位置在内的点的特殊情况。

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

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

相关文章

数据结构双向链表和循环链表

目录 一、循环链表二、双向链表三、循环双向链表 一、循环链表 循环链表就是首尾相接的的链表&#xff0c;就是尾节点的指针域指向头节点使整个链表形成一个循环&#xff0c;这就弥补了以前单链表无法在后面某个节点找到前面的节点&#xff0c;可以从任意一个节点找到目标节点…

5.3 克拉默法则、逆矩阵和体积

本节是使用代数而不是消元法来求解 A x b A\boldsymbol x\boldsymbol b Axb 和 A − 1 A^{-1} A−1。所有的公式都会除以 det ⁡ A \det A detA&#xff0c; A − 1 A^{-1} A−1 和 A − 1 b A^{-1}\boldsymbol b A−1b 中的每个元素都是一个行列式除以 A A A 的行列式。…

C(十一)scanf、getchar(第三弹)

问题引入&#xff1a;如何实现输入一串密码&#xff0c;如&#xff1a;“123 xxxx” &#xff0c;然后读取并确认&#xff0c;是 -- Y&#xff1b;否 -- N。 自然的&#xff0c;我们想到用scanf&#xff0c;但是在使用过程中你是否遇到跟我一样的困惑呢&#xff1f;如下&…

如何高效删除 MySQL 日志表中的历史数据?实战指南

在处理高并发的物联网平台或者其他日志密集型应用时&#xff0c;数据库中的日志表往往会迅速增长&#xff0c;数据量庞大到数百GB甚至更高&#xff0c;严重影响数据库性能。如何有效管理这些庞大的日志数据&#xff0c;特别是在不影响在线业务的情况下&#xff0c;成为了一项技…

【LeetCode HOT 100】详细题解之二叉树篇

【LeetCode HOT 100】详细题解之二叉树篇 94 二叉树的中序遍历方法一&#xff1a;递归方法二&#xff1a;迭代 104 二叉树的最大深度方法一&#xff1a;递归方法二&#xff1a;迭代 226 翻转二叉树方法一&#xff1a;递归方法二&#xff1a;迭代 101 对称二叉树方法一&#xff…

小程序-使用npm包

目录 Vant Weapp 安装 Vant 组件库 使用 Vant 组件 定制全局主题样式 API Promise化 1. 基于回调函数的异步 API 的缺点 2. 什么是 API Promise 化 3. 实现 API Promise 化 4.调用 Promise 化之后的异步 API 小程序对 npm 的支持与限制 目前&#xff0c;小程序中已经…

Java 之深入理解 String、StringBuilder、StringBuffer

前言 由于发现 String、StringBuilder、StringBuffer 面试的时候会经常问到&#xff0c;这里就顺便总结一下&#xff1a;本文重点会以这三个字符串类的性能、线程安全、存储结构这三个方面进行分析 ✨上期回顾&#xff1a;Java 哈希表 ✨目录 前言 String 介绍 String 的不可变…

全局安装cnpm并设置其使用淘宝镜像的仓库地址(地址最新版)

npm、cnpm和pnpm基本概念 首先介绍一下npm和cnpm是什么&#xff0c;顺便说一下pnpm。 npm npm&#xff08;Node Package Manager&#xff09;是Node.js的默认包管理器&#xff0c;用于安装、管理和分享JavaScript代码包。它是全球最大的开源库生态系统之一&#xff0c;提供了数…

如何使用ssm实现基于HTML的中国传统面食介绍网站的搭建+vue

TOC ssm758基于HTML的中国传统面食介绍网站的搭建vue 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔…

微服务SpringGateway解析部署使用全流程

官网地址&#xff1a; Spring Cloud Gateway 目录 1、SpringGateway简介 1、什么是网关 2、为什么用网关【为了转发】 2、应用&#xff1a; 1.启动nacos 2.创建网关项目 3.网关配置1 4.网关配置2【了解】 5.过滤器配置【了解】 1、SpringGateway简介 核心功能有三个&…

Webpack模式-Resolve-本地服务器

目录 ResolveMode配置搭本地服务器区分环境配置 Resolve 前面学习时使用了各种各样的模块依赖&#xff0c;这些模块可能来自于自己编写的代码&#xff0c;也可能来自第三方库&#xff0c;在 Webpack 中&#xff0c;resolve 是用于解析模块依赖的配置项&#xff0c;它决定了 We…

每日OJ题_牛客_DP13[NOIP2002 普及组]过河卒_路径dp_C++_Java

目录 牛客_DP13[NOIP2002 普及组]过河卒_路径dp 题目解析 C代码1 C代码2 Java代码 牛客_DP13[NOIP2002 普及组]过河卒_路径dp [NOIP2002 普及组] 过河卒_牛客题霸_牛客网 (nowcoder.com) 描述&#xff1a; 棋盘上 A点有一个过河卒&#xff0c;需要走到目标 B点。卒行走的…

业务封装与映射 -- 业务映射路径

为什么需要封装映射 OTN网络客户业务种类繁多&#xff08;例如SDH、以太网、视频&#xff09;&#xff0c;且业务大小不一&#xff08;例如STM-1、STM-4、STM-16&#xff09;&#xff0c;为了便于传输、管理客户业务&#xff0c;保证设备间互联互通&#xff0c;ITU-T定义了OTN接…

《深度学习》OpenCV 角点检测、特征提取SIFT 原理及案例解析

目录 一、角点检测 1、什么是角点检测 2、检测流程 1&#xff09;输入图像 2&#xff09;图像预处理 3&#xff09;特征提取 4&#xff09;角点检测 5&#xff09;角点定位和标记 6&#xff09;角点筛选或后处理&#xff08;可选&#xff09; 7&#xff09;输出结果 3、邻域…

物联网智能项目全面解析

目录 引言 一、物联网概述 1.1 什么是物联网 1.2 物联网的历史与发展 二、物联网智能项目分类 三、关键组件与技术 3.1 传感器和执行器 3.2 连接技术 3.3 数据处理与分析 3.4 用户界面 四、物联网智能项目案例分析 4.1 智能家居 4.2 智慧城市 4.3 工业物联网 4.4…

前端编程艺术(2)----CSS

目录 1.CSS 2.CSS引入 3.选择器 1.标签选择器 2.类选择器 3.id选择器 4.属性选择器 5.后代选择器 5.直接子元素选择器 6.伪类选择器 链接相关 动态伪类 结构化伪类 否定伪类 其他伪类 UI元素状态伪类 4.字体 1.font-family 2.font-size 3.font-style 4.fo…

C++之多线程

前言 多线程和多进程是并发编程的两个核心概念,它们在现代计算中都非常重要,尤其是在需要处理大量数据、提高程序性能和响应能力的场景中。 多线程的重要性: 资源利用率:多线程可以在单个进程中同时执行多个任务,这可以更有效地利用CPU资源,特别是在多核处理器上。 性…

奔驰EQS450suv升级增强AR抬头显示HUD案例分享

以下是奔驰 EQS450 SUV 升级增强版 AR 抬头显示的一般改装案例步骤及相关信息&#xff1a; 配件&#xff1a;通常包括显示屏、仪表模块、饰板等。 安装步骤&#xff1a; 1. 拆下中控的仪表。 2. 在仪表上预留位置切割出合适的孔位&#xff0c;用于安装显示器。 3. 将显示器…

(IDEA)spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案

系列文章目录 文章目录 系列文章目录一、&#xff08;IDEA&#xff09;spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案1.资料 一、&#xff08;IDEA&#xff09;spring项目导入本地jar包方法和项目打包时找不到引入本地jar包的问题解决方案 1.资料…

Python案例--水仙花数的探索之旅

一、引言 水仙花数&#xff0c;也称为阿姆斯特朗数&#xff0c;是一种特殊的三位数&#xff0c;其各位数字的立方和等于其本身。例如&#xff0c;153就是一个水仙花数&#xff0c;因为 135333153135333153。这种数字的发现不仅展示了数字的内在美&#xff0c;也激发了人们对数…