1.地下城游戏
https://leetcode-cn.com/problems/dungeon-game/
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 (P)
说明:
骑士的健康点数没有上限。
任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
思路:采用反向dp,从终点开始,直至推到起点处,注意每个位置的最低血量至少要是1
class Solution {
public int calculateMinimumHP(int[][] dungeon) {
if(dungeon==null||dungeon.length==0||dungeon[0].length==0){
return 0;
}
int row=dungeon.length,col=dungeon[0].length;
int[][] dp=new int[row][col];
//终点处的最低血量
dp[row-1][col-1]=Math.max(1,1-dungeon[row-1][col-1]);
//对最后一列赋初值
for(int i=row-2;i>=0;i--){
dp[i][col-1]=Math.max(1,dp[i+1][col-1]-dungeon[i][col-1]);
}
//对最后一行赋初值
for(int i=col-2;i>=0;i--){
dp[row-1][i]=Math.max(1,dp[row-1][i+1]-dungeon[row-1][i]);
}
//每个点的最低血量取到这个点下方和右侧一点其中的最小值,然后再和1比较取较大值
for(int i=row-2;i>=0;i--){
for(int j=col-2;j>=0;j--){
dp[i][j]=Math.max(1,Math.min(dp[i+1][j]-dungeon[i][j],dp[i][j+1]-dungeon[i][j]));
}
}
return dp[0][0];
}
}
2.不同路径
https://leetcode-cn.com/problems/unique-paths/
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
提示:
1 <= m, n <= 100
题目数据保证答案小于等于 2 * 10 ^ 9
思路:动态规划从起点开始,求解至终点
class Solution {
public int uniquePaths(int m, int n) {
if(m==0||n==0){
return 0;
}
//dp[i][j]表示到点(i,j)处的路径数
int [][]dp=new int[n][m];
//到起点的路径数是1
dp[0][0]=1;
//第一行的每个点路径数都是1
for(int i=1;i<m;i++){
dp[0][i]=1;
}
//第一列的每个点路径数都是1
for(int i=1;i<n;i++){
dp[i][0]=1;
}
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
//到某点的路径数等于到其左侧一点路径数加上到其上方一点的路径数
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[n-1][m-1];
}
}
3.不同路径 II
https://leetcode-cn.com/problems/unique-paths-ii/
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
思路:判断每个点是否有障碍,有障碍的点路径数都为0,其余同上题
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if(obstacleGrid==null||obstacleGrid.length==0||obstacleGrid[0].length==0){
return 0;
}
int row=obstacleGrid.length;
int col=obstacleGrid[0].length;
//若起点或终点处有障碍,则路径数为0输出
if(obstacleGrid[0][0]==1||obstacleGrid[row-1][col-1]==1){
return 0;
}
//dp[i][j]表示到点(i,j)处的路径数
int [][]dp=new int[row][col];
dp[0][0]=1;
//第一行赋初值
for(int i=1;i<col;i++){
//若该点有障碍则路径数为0
if(obstacleGrid[0][i]==1){
dp[0][i]=0;
}
else{
//到该点路径数同到该点左侧点路径数
dp[0][i]=dp[0][i-1];
}
}
for(int i=1;i<row;i++){
if(obstacleGrid[i][0]==1){
dp[i][0]=0;
}
else{
//到该点路径数同到该点上方点路径数
dp[i][0]=dp[i-1][0];
}
}
for(int i=1;i<row;i++){
for(int j=1;j<col;j++){
//该点有障碍则路径数为0
if(obstacleGrid[i][j]==1){
dp[i][j]=0;
}
else{
//到该点路径数等于到其左侧和上方一点的路径数和
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
}
return dp[row-1][col-1];
}
}