如果你对动态规划不熟悉,望转到该篇 \color{red}{如果你对动态规划不熟悉,望转到该篇~}如果你对动态规划不熟悉,望转到该篇 

肝了好多天-动态规划十连-超细腻解析|刷题打卡

这道题很经典啦???????????? \color{green}{这道题很经典啦???? ???? ???? ~}这道题很经典啦???????????? 

什么题可以选择动态规划来做?

1.计数

  • 有多少种方式走到右下角
  • 有多少种方法选出k个数是的和是sum

2.求最大值最小值

  • 从左上角走到右下角路径的最大数字和
  • 最长上升子序列长度

3.求存在性

  • 取石子游戏,先手是否必胜
  • 能不能选出k个数使得和是sum

4.综合运用

  • 动态规划 + hash
  • 动态规划 + 递归
  • ...

leecode 174. 地下城游戏

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。

我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快到达公主,骑士决定每次只向右或向下移动一步。

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

如果走其他路径,初始的健康点数都是>7的。

动态规划-详解地下城游戏_后端

说明:

骑士的健康点数没有上限。

任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。


--

❤️❤️❤️❤️

2.1. 动态规划组成部分1:确定状态

简单的说,解动态规划的时候需要开一个数组,数组的每个元素f[i]或者f[i][j]代表什么,类似数学题中x, y, z代表什么

最后一步

我们定义dp[i][j] 表示从坐标 (i,j) 到终点所需的最小初始值

很明显,想要救出公主,我们必须保证到达某个坐标时(i,j)时,走过的路径和要大于当前坐标

第二,骑士要么走右[i + 1][j], 要么走下[i][j+1] , 所以我们只需要知道这两种情况的较小值就可以了。

其实这道题,公主救骑士比较好

那么最后一步就是从[2][2]、[2][1]、[2][0]、[1][2]、[1][1]、[1][0]、[0][2]、[0][1]、[0][0]

自然而然,最后一步就是[0][0]了。

1.2. 动态规划组成部分2:转移方程

dp[i][j]=max ( min(dp[i+1][j],dp[i][j+1]) −dungeon(i,j),1)

dungeon(i,j) 为当前坐标的值

1.3. 动态规划组成部分3:初始条件和边界情况

初始都给MAX_VALUE

for (int i = 0; i <= n; ++i) {
     Arrays.fill(dp[i], Integer.MAX_VALUE); // 填充每个值都为MAX_VALUE。
}

复制代码

当 i=n-1 或者 j=m-1 时

dp[n][m - 1] = dp[n - 1][m] = 1; // 即救出后还要剩余最后一滴血

1.4. 动态规划组成部分4:计算顺序

公主救骑士

公主快跑???????????? \color{green}{公主快跑???? ???? ???? ~}公主快跑???????????? 

参考代码

GO语言版

func calculateMinimumHP(dungeon [][]int) int {
    n, m := len(dungeon), len(dungeon[0])
    dp := make([][]int, n + 1)
    for i := 0; i < len(dp); i++ {
        dp[i] = make([]int, m + 1)
        for j := 0; j < len(dp[i]); j++ {
            dp[i][j] = math.MaxInt32
        }
    }
    dp[n][m - 1], dp[n - 1][m] = 1, 1
    for i := n - 1; i >= 0; i-- {
        for j := m - 1; j >= 0; j-- {
            minn := min(dp[i+1][j], dp[i][j+1])
            dp[i][j] = max(minn - dungeon[i][j], 1)
        }
    }
    return dp[0][0]
}

func min(x, y int) int {
    if x < y {
        return x
    }
    return y
}

func max(x, y int) int {
    if x > y {
        return x
    }
    return y
}




复制代码

NICE???????????? \color{red}{NICE???? ???? ???? ~}NICE???????????? 

java版

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


复制代码

❤️❤️❤️❤️