【动态规划】矩阵

1. 题目列表

序号 题目 难度
1 64. 最小路径和 中等
2 174. 地下城游戏 困难

2. 应用

2.1. Leetcode 64. 最小路径和

2.1.1. 题目

64. 最小路径和

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。

示例 1:

image
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

2.1.2. 分析

这里,我们使用动态规划的思路求解,我们假设 dp[i][j] 表示到达位置 (i,j) 的最小路径和,同时,假设 mn 分别表示矩阵的高和宽。

2.1.2.1. 边界条件

当矩阵的大小为 1 时,那么,最小的路径,就是当前网格中的数值,即

dp[0][0]=grid[0][0]

当矩阵只有一列时,最小路径和,就是这一列的数值之和,即

dp[i][0]=dp[i1][0]+grid[i][0],i1

当矩阵只有一行时,最小路径和,就是这一行的数值之和,即

dp[0][j]=dp[0][j1]+grid[0][j],j1

2.1.2.2. 状态转移

我们容易看出来,当 1i<n1j<n 时,在矩阵中的任意一个位置,都有

dp[i][j]=min(dp[i1][j],dp[i][j1])+grid[i][j],1i<n,1j<n

2.1.3. 代码实现

class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length, n = grid[0].length;
int [][] dp = new int[m][n];
dp[0][0] = grid[0][0];
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int j = 1; j < n; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[m - 1][n - 1];
}
}

2.2. Leetcode 174. 地下城游戏

2.2.1. 题目

174. 地下城游戏

恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若 房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快解救公主,骑士决定每次只 向右向下 移动一步。
返回确保骑士能够拯救到公主所需的最低初始健康点数。
注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

示例 1:

image

输入:dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

2.2.2. 分析

题目中要求骑士的血量等于或小于 0 就会死亡,也就是说,在每一个位置,骑士最少的血量至少为 1

我们可以考虑,从终点逆向返回起点,如果它,计算每一个位置会消耗的血量,就可以得到起始位置骑士的初始血量了。

我们,假设 dp[i][j] 表示骑士从位置 (i,j) 出发,到达终点位置所需要的最少初始血量,同时,假设 mn 分别表示矩阵的高和宽。

2.2.2.1. 初始条件

显然,如果骑士位于终点,即 (m1,n1) ,那么,他下一个可以到达的位置就是 (m,n1) 或者 (m1,n),这是两个矩阵之外的无效位置,为了方便计算,我们假设这两个位置不消耗血量,因此,到达这两个位置他所需要的最少血量为 1,因此,有

dp[m][n1]=1dp[m1][n]=1

2.2.2.2. 状态转移

我们从某一个位置 (i,j) 前进时,骑士只能向左或者向下两个方向可以移动,即下一个位置只能是 (i+1,j) 或者 (i,j+1),这里,只需要关注从这两个位置到达终点的最小血量即可。

也就是说,我们在位置 (i,j) 的初始血量只需要达到 min(dp[i+1][j],dp[i][j+1])dungeon[i][j] 即可。

同时,我们还需要保证每一个位置的最少血量大于等于 1,因此,当前位置需要的最少血量就是:

dp[i][j]=max(min(dp[i+1][j], dp[i][j+1])dungeon[i][j],1),0im1,0jn1

2.2.3. 代码实现

class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int m = dungeon.length, n = dungeon[0].length;
int [][] dp = new int [m + 1][n + 1];
for(int [] row : dp) {
Arrays.fill(row, Integer.MAX_VALUE);
}
dp[m][n - 1] = 1;
dp[m - 1][n] = 1;
for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
dp[i][j] = Math.max(Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j], 1);
}
}
return dp[0][0];
}
}

本文作者:LARRY1024

本文链接:https://www.cnblogs.com/larry1024/p/17984317

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   LARRY1024  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.