【动态规划Ⅲ】二维数组的动态规划——start到finish的不同路径

不同路径

62. 不同路径

62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径

这个题目是要找到,从左上角到右下角,有多少条路径。题目中给出了每次挪动的两种选择:向下or向右。 用二维数组dp[i][j]记录到达下标为[i][j]位置的路径数量,那么dp[i][j] = dp[i-1][j] + dp[i][j-1]。同时这个题目和64. 最小路径和的更新方式一样,可以用一维dp记录:dp[j] += dp[j-1]。 java代码如下:

class Solution {
    public int uniquePaths(int m, int n) {
        int pathSum[] = new int[n];
        // 第一行只能从左边的点往右移动,路径只有一种
        for(int i =0; i < n; i++)
            pathSum[i]=1;       
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++)
                pathSum[j] += pathSum[j-1];
        return pathSum[n-1];
    }
}

63. 不同路径 II

63. 不同路径 II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径
网格中的障碍物和空位置分别用 1 和 0 来表示。

这个题目在上一个题目的基础上,加了一个限制:有障碍物。那么更新过程中,如果obstacleGrid[i][j] == 1,表示有障碍物,那么dp[i][j] = 0,其他情况和上一题更新过程是一样的!
Java代码:

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
    	// 
        if(obstacleGrid[0][0] == 1)
            return 0;
        int m =obstacleGrid.length, n = obstacleGrid[0].length;
        int[] pathSum = new int[n];
        // 更新start的路径数
        pathSum[0] = obstacleGrid[0][0] == 0? 1 : 0;
		//更新pathSum
        for(int i = 0; i < m; i++){          
            for(int j = 0; j < n; j++)
            	// 遇到障碍物,路径数变为0
                if(obstacleGrid[i][j] == 1){
                    pathSum[j] = 0;
                }
                // 非障碍物更新路径数
                else if(j >=1)
                    pathSum[j] += pathSum[j-1];                
        }
        return pathSum[n-1];
    }
}

变形难题

174. 地下城游戏

174. 地下城游戏

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

理解题意,骑士需要一个初始健康点数,然后活着从左上角走到右下角,去拯救公主。每次只能向下or向右走一步,经过的格子里面可能是负数,那么骑士健康点会下降,有死掉的可能性。
我们从左上角开始进行动态规划,那么每个点需要记录到这个点需要的最小健康初值外,还需要记录到当前点的和,然而到一个点可以经过其左边or上边的点,这两个路径中,可能一个健康初值小,而另外一个健康值和更大,这两个因素都十分重要。比如官方题解给的这个例子:
在这里插入图片描述
蓝色路径到达当前点所需最小健康初值为3,和为1;
绿色路径到达当前点所需最小健康初值为2,和为-1;
如果重点是健康初始值的大小,那么选择蓝色路径,但是由于其和只有-1,重点右下角为-2,所需健康初值变成4;但是从绿色路径到右下角,只需要初始健康值3个即可,因为其和更大。
但是如果右下角是0,蓝色路径就是更优的。
因此从左上开始动态规划有问题,那就考虑从右下角开始。此时dp[i][j]表示以这个点为起点,能够或者到达右下角所需的最低健康初始值。dp[i][j] 与p[i+1][j]和dp[i][j+1]相关,因为是需要的最低健康初值,那么自然是dp[i+1][j]和dp[i][j+1]中更小的那一个,但是最后怎么更新呢? 如果dungeon[i][j]是负数,那么自然加上这个负数的绝对值,表示所需的健康初值要增加,但是如果dungeon[i][j]是正数,dp[i][j]所需的最低健康初值就可以在min(dp[i+1][j], dp[i][j+1])的基础上减去这个正数,但是需要保证健康初值最低为1(因为是一个正数),因此状态转移:dp[i][j] =max (min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j] , 1)
首先从右下角开始,那么dp初始化就需要比dungeon多一行多一列,这多出来的一行一列全部初始化为Integer.MAX_VALUE,但是dp[m][n-1],dp[m-1][n]需要初始化为1。完整Java代码如下:

class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        int rows =dungeon.length, cols = dungeon[0].length;
        int[][] counts = new int[rows+1][cols+1];
        for (int i = 0; i <= rows; ++i) {
            Arrays.fill(counts[i], Integer.MAX_VALUE);
        }
        counts[rows][cols-1] = 1;
        counts[rows-1][cols] = 1;
        for(int i = rows-1; i >=0 ; i--){
            for(int j = cols-1; j>=0; j--){
                counts[i][j] = Math.max(1, Math.min(counts[i][j+1],counts[i+1][j]) - dungeon[i][j]);
            }
        }
        return counts[0][0];
    }
}

741. 摘樱桃

741. 摘樱桃
占个坑,不会。题解也没看懂………………

  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值