动态规划之网格图模型(二)

article/2025/6/7 22:34:11

文章目录

  • 动态规划之网格图模型(二)
    • LeetCode 931. 下降路径最小和
      • 思路
      • Golang 代码
    • LeetCode 2684. 矩阵中移动的最大次数
      • 思路
      • Golang 代码
    • LeetCode 2304. 网格中的最小路径代价
      • 思路
      • Golang 代码
    • LeetCode 1289. 下降路径最小和 II
      • 思路
      • Golang 代码
    • LeetCode 3418. 机器人可以获得的最大金币数
      • 思路
      • Golang 代码

动态规划之网格图模型(二)

今天我们继续学习动态规划当中的网格图模型。
在这里插入图片描述

LeetCode 931. 下降路径最小和

思路

题目中已经提到,下降路径可以从这一行当中的任何一个元素开始,也就意味着在一条路径上,某一行的某个元素的上一个元素是它正上方、左上方、右上方某个元素。根据这条性质,我们使用二维数组dp表示(i, j)这个位置的子路径和,据此我们可以写出状态转移方程:dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1], dp[i - 1][j + 1]) + matrix[i][j]。注意处理边界情况,也就是元素位于左边界和右边界时,左上方或右上方的元素取不到,因为如果取到的话数组就越界了。

最后取最后一行的最小值,就是最终答案。

Golang 代码

func minFallingPathSum(matrix [][]int) int {m, n := len(matrix), len(matrix[0])dp := make([][]int, m)for i := 0; i < m; i ++ {dp[i] = make([]int, n)}for i := 0; i < n; i ++ {dp[0][i] = matrix[0][i]}for i := 1; i < m; i ++ {for j := 0; j < n; j ++ {if j == 0 {dp[i][j] = min(dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j]} else if j == n - 1 {dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j]) + matrix[i][j]} else {dp[i][j] = min(dp[i - 1][j -  1], dp[i - 1][j], dp[i - 1][j + 1]) + matrix[i][j]}}}return slices.Min(dp[m - 1])
}

LeetCode 2684. 矩阵中移动的最大次数

思路

这道题可以使用 DFS 或 BFS 来解决,也可以使用 DP 来解决。 具体来说,最开始我们可以从矩阵第一列的任何位置开始移动,每次只能移动到右、右上、右下三个位置,且移动到的位置需要满足那个位置的元素大于当前位置的元素。通过观察不难发现,能够在矩阵中移动的最大次数等于矩阵的总列数,也就是说,最大次数对应的移动方案就是从第一列移动到最后一列。

如果我们使用 DP,那么可以使用一个二维的数组dp来记录元素(i, j),是否是「可到达的」,因此dp保存的是 bool 值。初始状态下,第一列的所有元素都是可以到达的,所以我们令第一列的 bool 值都为 true。从第二列开始,我们判断每一行的元素是否可到达,判断的依据是当前元素左侧的那一列上是否有满足条件的元素使得从那个元素可以到达当前元素。

由于我们使用 DP 的思路来解题,因此应该反向思考,要到达(i, j),就需要(i, j - 1)(i - 1, j - 1)以及(i + 1, j - 1)当中的一个或多个满足grid[ni][nj] < grid[i][j],这样(i, j)才是可达的。

在遍历某一列的每一行之前,使用一个 bool 值reachable来判断这一列是否可达,如果这一列不可达,那么就没必要继续向右侧的列遍历了,直接返回答案即可。

如果所有列都可达,那么答案就是n - 1,其中n是列数。

Golang 代码

func maxMoves(grid [][]int) int {m, n := len(grid), len(grid[0])dp := make([][]bool, m)for i := 0; i < m; i ++ {dp[i] = make([]bool, n)}// 第一行都是可达的, 对第一行进行初始化for i := 0; i < m; i ++ {dp[i][0] = true}for j := 1; j < n; j ++ {var reachable bool = falsefor i := 0; i < m; i ++ {if dp[i][j - 1] && grid[i][j - 1] < grid[i][j] {dp[i][j] = truereachable = true} else if i >= 1 && dp[i - 1][j - 1] && grid[i - 1][j - 1] < grid[i][j] {dp[i][j] = truereachable = true} else if i <= m - 2 && dp[i + 1][j - 1] && grid[i + 1][j - 1] < grid[i][j] {dp[i][j] = truereachable = true}}if !reachable {return j - 1}}return n - 1
}   

LeetCode 2304. 网格中的最小路径代价

思路

这道题的题目描述非常的复杂,实际上这道题在说的就是从第一行出发,寻找一个到达最后一行的最小代价。最小代价保存在moveCost数组当中,moveCost[i][j]代表的含义就是从值为i的点出发到达下一行第j列的代价。为了更好地理解moveCost,我们以图中值为5的点为例,它在moveCost中的位置就是moveCost[5],由于它位于第一行,因此从它开始到达第二行的40的代价分别是143

讲清楚了问题描述,我们现在就可以开始着手解决问题。仍然使用网格图 DP 的思路来解决当前问题,具体来说,设置一个二维的数组dp,用来记录从「最后一行」开始到达(i, j)位置的最小代价。这里重点强调一下最后一行,因为我们要使用自底向上的思路来解决当前问题,最终的答案是dp[0]这一行的最小值。

dp[i][j]的构成有三部分,第一部分就是从它的下一行某个元素k到达(i, j)的路径代价c,第二部分是从下一行元素已经积累的代价dp[i + 1][k],第三部分是(i, j)本身的值grid[i][j]。汇总三部分可以得到状态转移方程:dp[i][j] = dp[i + 1][k] + c + grid[i][j]。需要再次强调的是,我们使用自底向上的方式来解决问题,所以答案是自底向上更新的。

Golang 代码

func minPathCost(grid [][]int, moveCost [][]int) int {m, n := len(grid), len(grid[0])dp := make([][]int, m)for i := 0; i < m; i ++ {dp[i] = make([]int, n)}// 自底向上, 因此先初始化最后一行的值dp[m - 1] = grid[m - 1]// 最后的答案是 dp 数组第一行的最小值for i := m - 2; i >= 0; i -- {for j := 0; j < n; j ++ {val := grid[i][j]dp[i][j] = math.MaxIntfor k, c := range moveCost[val] {// moveCost 记录的就是从 (i, j) 出发到达下一行第 k 列的那个位置的代价dp[i][j] = min(dp[i][j], dp[i + 1][k] + c)}dp[i][j] += val // 最后需要加上当前位置的值}}return slices.Min(dp[0])
}

LeetCode 1289. 下降路径最小和 II

思路

这道题目与普通版本的「最小路径下降和」比较相似,较大的变化在于当前(i, j)的和可以与上一行的任意列的值累加,且相邻行所选的列不能重复。

我们使用 DP 来解决问题,使用二维数组dp来记录(i, j)位置的最小路径和。由于该位置可以由上一行除j以外任意位置到达,因此我们使用第三重循环来寻找该行最小的路径和,累加得到答案即可。

最终的答案是最后一行的最小值。

Golang 代码

func minFallingPathSum(grid [][]int) int {m, n := len(grid), len(grid[0])dp := make([][]int, m)for i := 0; i < m; i ++ {dp[i] = make([]int, n)}dp[0] = grid[0]for i := 1; i < m; i ++ {dp[i] = grid[i]for j := 0; j < n; j ++ {var val int = math.MaxIntfor k := 0; k < n; k ++ {if j == k {continue}val = min(val, dp[i - 1][k])}dp[i][j] += val}}return slices.Min(dp[m - 1])
}

LeetCode 3418. 机器人可以获得的最大金币数

思路

使用网格图 DP 来解决该问题。每多一个约束条件,DP 数组就应该增加一个维度。对于本题而言,新增加的约束就是「最多可以感化两个单元格」,也就是「最多有两个单元格可以不选」。我们使用三维数组dp来解决问题。第一个和第二个维度对应的是网格图的维度,而第三个维度对应的是「选/不选」的约束。

对于前两个维度而言,(i, j)位置的答案可以由(i - 1, j)(i, j - 1)贡献得到。而对于第三个维度,由于题目已经限定「不选」的最大次数是 2,因此dp[i][j][0]指的就是全选的情况,dp[i][j][1]对应的就是有一次不选的情况,dp[i][j][2]对应的是有两次不选的情况。这一部分的状态更新可以详见代码。

Golang 代码

func maximumAmount(coins [][]int) int {m, n := len(coins), len(coins[0])dp := make([][][3]int, m + 1)for i := 0; i <= m; i ++ {dp[i] = make([][3]int, n + 1)}for i := 0; i <= m; i ++ {dp[i][0] = [3]int{math.MinInt / 2, math.MinInt / 2, math.MinInt / 2}}for i := 0; i <= n; i ++ {dp[0][i] = [3]int{math.MinInt / 2, math.MinInt / 2, math.MinInt / 2}}dp[0][1] = [3]int{}for i := 1; i <= m; i ++ {for j := 1; j <= n; j ++ {x := coins[i - 1][j - 1]dp[i][j][0] = max(dp[i - 1][j][0] + x, dp[i][j - 1][0] + x)dp[i][j][1] = max(dp[i - 1][j][1] + x, dp[i][j - 1][1] + x, dp[i - 1][j][0], dp[i][j - 1][0])dp[i][j][2] = max(dp[i - 1][j][2] + x, dp[i][j - 1][2] + x, dp[i - 1][j][1], dp[i][j - 1][1])}}return dp[m][n][2]
}

http://www.hkcw.cn/article/GFSKlNbMkU.shtml

相关文章

QUIC——UDP实现可靠性传输

首先我们要知道TCP存在什么样的痛点问题 TCP的升级很困难TCP建立连接的延迟网络迁移需要重新建立连接TCP存在队头阻塞问题 QUIC就是为了解决以上的问题而诞生了, 下面我会介绍QUIC的一些特性和原理 QUIC对比TCP优势: 握手建连更快 QUIC内部包含了TLS, 它在自己的帧会携带TL…

PyTorch——线性层及其他层介绍(6)

线性层 前面1,1,1是你想要的&#xff0c;后面我们不知道这个值是多少&#xff0c;取-1让Python自己计算 import torch import torchvision from torch import nn from torch.nn import Linear from torch.utils.data import DataLoader# 加载CIFAR-10测试数据集并转换为Tensor格…

bilibili批量取消关注

目录 如何使用 ​编辑 代码 如何使用 使用谷歌浏览器&#xff0c;通过F12打开调式面板&#xff0c;找到下面的位置&#xff1a; 代码 /*** 批量取消关注脚本* 自动遍历多页内容并取消所有关注*/// 配置常量 const CONFIG {CLICK_DELAY: 250, // 点击间隔时间&#…

7.RV1126-OPENCV cvtColor 和 putText

一.cvtColor 1.作用 cvtColor 是 OPENCV 里面颜色转换的转换函数。能够实现 RGB 图像转换成灰度图、灰度图转换成 RGB 图像、RGB 转换成 HSV 等等 2.API CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn 0 ); 第一个参数&#xff1a;…

研发型企业如何面对源代码保密问题

在当今数字化时代&#xff0c;研发团队面临着数据安全和工作效率的双重挑战。技术成果和源代码不仅是企业的核心资产&#xff0c;更是企业竞争力的基石。然而&#xff0c;数据泄露的风险无处不在&#xff0c;从内部员工的无意失误到外部攻击者的恶意窃取&#xff0c;都可能给企…

BeeWorks:私有化即时通讯,筑牢企业信息安全防线

在数字化时代&#xff0c;即时通讯已成为企业日常运营中不可或缺的工具。然而&#xff0c;数据安全问题一直是企业使用即时通讯服务时的重要考量因素。BeeWorks即时通讯系统以其私有化部署模式&#xff0c;为企业提供了一个安全、可靠、自主可控的沟通平台。 私有化部署&#…

akka实践之应用的扩展性问题和actor模型

如何解决应用的扩展性问题 当一个应用需要处理海量并发请求时&#xff0c;传统的开发模式往往显得力不从心&#xff0c;为什么应用需要扩展性&#xff1f; 需求增长: 用户量激增&#xff0c;数据量爆炸式增长。资源限制: 服务器、带宽、存储等资源有限。复杂性增加: 代码逻辑…

Starrocks Full GC日志分析

GC日志样例&#xff1a; [2025-06-03T07:36:06.1770800] GC(227) Pause Full (G1 Evacuation Pause) [2025-06-03T07:36:06.1960800] GC(227) Phase 1: Mark live objects [2025-06-03T07:36:06.9480800] GC(227) Cleaned string and symbol table, strings: 47009 processed,…

mapbox高阶,生成并加载等时图

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️Fill面图层样式1.4 ☘️symbol符号图层…

防火墙在OSI模型中的层级工作(2025)

1. 物理层&#xff08;L1&#xff09;& 数据链路层&#xff08;L2&#xff09; 传统防火墙&#xff1a;通常不处理L1/L2&#xff08;由交换机/网卡负责&#xff09;。 现代演进&#xff1a; MAC地址过滤&#xff1a;部分防火墙支持基于MAC地址的粗粒度策略&#xff08;如禁…

帝可得 - 运营管理APP

Android模拟器 本项目的App客户端部分已经由前端团队进行开发完成&#xff0c;并且以apk的方式提供出来&#xff0c;供我们测试使用&#xff0c;如果要运行apk&#xff0c;需要先安装安卓的模拟器。 可以选择国内的安卓模拟器产品&#xff0c;比如&#xff1a;网易mumu、雷电…

关于list集合排序的常见方法

目录 1、list.sort() 2、Collections.sort() 3、Stream.sorted() 4、进阶排序技巧 4.1 空值安全处理 4.2 多字段组合排序 4.3. 逆序 5、性能优化建议 5.1 并行流加速 5.2 原地排序 6、最佳实践 7、注意事项 前言 Java中对于集合的排序操作&#xff0c;分别为list.s…

自然语言处理(NLP)的系统学习路径规划

文章目录 一、基础准备阶段&#xff08;1-2个月&#xff09;1. 数学基础2. 编程基础3. 语言学基础 二、核心技术阶段&#xff08;3-4个月&#xff09;1. 经典NLP技术2. 深度学习模型3. 预训练模型入门 三、进阶实战阶段&#xff08;2-3个月&#xff09;1. 热门任务实战2. 大模型…

CSS3美化页面元素

1. 字体 <span>标签 字体样式⭐ 字体类型&#xff08;font-family&#xff09; 字体大小&#xff08;font-size&#xff09; 字体风格&#xff08;font-style&#xff09; 字体粗细&#xff08;font-weight&#xff09; 字体属性&#xff08;font&#xff09; 2. 文本 文…

便签软件哪个好用,最好用的免费便签软件介绍

在快节奏的工作和生活中&#xff0c;一款好用的便签软件能帮助我们高效记录灵感、管理待办事项&#xff0c;甚至成为个人生产力系统的核心工具。2025年&#xff0c;市面上涌现了许多优秀的免费便签软件&#xff0c;它们各具特色&#xff0c;能满足不同用户的需求。便签软件哪个…

如何轻松删除 Android 上的文件(3 种方法)

Android 手机是非常强大的设备&#xff0c;可让我们存储大量的个人数据&#xff0c;从照片和视频到应用程序和文档。然而&#xff0c;随着时间的推移&#xff0c;您的设备可能会因不再需要的文件而变得混乱。删除这些文件有助于释放空间并提高性能。在本指南中&#xff0c;我们…

鸿蒙简易版影视APP案例实战

目录 1. 案例效果 2. 资源初始化和资源文件 2.1. string.json (en_US) 2.2. string.json (zh_CN) 2.3. constants 3. 视频列表 3.1. 顶部导航 3.1.1. TobBar 组件 3.1.2. TopBar 数据源 3.2. 全部分类内容页面 3.2.1. 全部分类组件 3.2.2. 轮播图组件 3.2.3. 图片列…

对于python中“FileNotFoundError: [Errno 2] No such file or directory”的解决办法

写在前面 最近在使用 vscode 写代码 (python) 时发现使用相对路径读取文件以及写入文件时&#xff0c;想要直接在当前目录下读写一直提示没有该文件&#xff0c;需要返回根目录。并且使用 vscode 自带调试"F5"以及 Code Runner 扩展即右上角三角形都是如此。参考了许…

VS2022中配置Anaconda3环境和scikit-learn库

VS2022中配置Anaconda3环境和scikit-learn库 安装Anaconda安装scikit-learn库在VS2022中配置该环境 安装Anaconda 1.双击应用程序开始安装 2.点击Next 3.I Agree 4.Just Me 5.修改安装路径到D盘 6.没有选择自动配置环境变量&#xff0c;点击Install安装 7.安装完成 8.进…

Q:知识库-文档的搜索框逻辑是怎样的?

【回到目录】~~~~【回到问题集】 Q&#xff1a;知识库-文档的搜索框逻辑是怎样的? dify知识库的关键字检索响应速度很快,效果如上图 A&#xff1a;查看源代码&#xff0c;搜索逻辑是通过搜索框查看 document_segments.content字段满足条件的记录 , 程序逻辑参考 datasets_se…