Leetcode.174 地下城游戏

题目链接

Leetcode.174 地下城游戏 hard

题目描述

恶魔们抓住了公主并将她关在了地下城 d u n g e o n dungeon dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

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

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

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

返回确保骑士能够拯救到公主所需的最低初始健康点数。

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

示例 1:

输入:dungeon = \[-2,-3,3,-5,-10,1,10,30,-5]

输出:7

解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

示例 2:

输入:dungeon = \[0]

输出:1

提示:

  • m = d u n g e o n . l e n g t h m = dungeon.length m=dungeon.length
  • n = d u n g e o n i . l e n g t h n = dungeoni.length n=dungeoni.length
  • 1 ≤ m , n ≤ 200 1 \leq m, n \leq 200 1≤m,n≤200
  • − 1000 ≤ d u n g e o n i j ≤ 1000 -1000 \leq dungeonij \leq 1000 −1000≤dungeonij≤1000

解法:动态规划

假设我们考虑从左上角到右下角 ,这样的话我们需要考虑两个因素:当前路径和当前路径上的最小路径和。因为存在两个同等重要的因素,所以我们无法确定下一个位置。

既然从左上角到右下角不行,那么我们就考虑从右下角到左上角。

考虑从右下角到左上角 ,我们定义 f ( i , j ) f(i,j) f(i,j) 为从位置 ( i , j ) (i,j) (i,j) 到终点 ( m − 1 , n − 1 ) (m-1,n-1) (m−1,n−1)所需要的最低初始健康点数。按照定义,最终我们返回的结果就是 f ( 0 , 0 ) f(0,0) f(0,0)。

f ( i , j ) f(i,j) f(i,j) 只与 f ( i + 1 , j ) f(i + 1,j) f(i+1,j) 和 f ( i , j + 1 ) f(i,j+1) f(i,j+1) 以及 d u n g e o n i j dungeonij dungeonij 有关。

即 f ( i , j ) = m i n { f i + 1 j , f i j + 1 } − d u n g e o n i j f(i,j) = min \{ fi + 1j , fij + 1 \} - dungeonij f(i,j)=min{fi+1j,fij+1}−dungeonij

因为 f i j fij fij 必须是 ≥ 1 \geq1 ≥1 的,所以最终的转移方程为:

f ( i , j ) = m a x { m i n ( f i + 1 j , f i j + 1 ) − d u n g e o n i j , 1 } f(i,j) = max \{ min ( fi + 1j , fij + 1 ) - dungeonij,1\} f(i,j)=max{min(fi+1j,fij+1)−dungeonij,1}

当 i = m − 1 i =m - 1 i=m−1 或者 j = n − 1 j = n- 1 j=n−1时, f i + 1 j fi+1j fi+1j 和 f i j + 1 fij+1 fij+1 就会分别越界。初始直接定义 f i j fij fij 为一个较大的值,这里我设置的是 1 0 9 10^9 109。

特别需要注意的是,我们直接把 f m n − 1 fmn-1 fmn−1 和 f m − 1 n fm-1n fm−1n 设置为 1 1 1,这样是为了让 f m − 1 n − 1 = d u n g e o n m − 1 n − 1 fm-1n-1 = dungeonm-1n-1 fm−1n−1=dungeonm−1n−1

时间复杂度: O ( m × n ) O(m \times n) O(m×n)

C++代码:

cpp 复制代码
class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& g) {
        int m = g.size() , n = g[0].size();
        vector<vector<int>> f(m + 1,vector<int>(n + 1,1e9));

        f[m][n - 1] = 1;
        f[m - 1][n] = 1;

        for(int i = m - 1;i >= 0;i--){
            for(int j = n - 1;j >= 0;j--){
                int t = min(f[i + 1][j],f[i][j + 1]);
                f[i][j] = max(t - g[i][j] , 1);
            }
        }

        return f[0][0];
    }
};
相关推荐
旖-旎12 小时前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
tkevinjd20 小时前
力扣300-最长递增子序列
算法·leetcode·职场和发展·动态规划·贪心
学究天人1 天前
数学公理体系大全:第十四章 向量空间与模:线性代数的公理化与推广
线性代数·算法·矩阵·动态规划·抽象代数
星马梦缘2 天前
算法设计 期末复习笔记
算法·动态规划·二分图·最小生成树·线性规划·最大流
学究天人2 天前
数学公理体系大全:第七章 连续统假设与力迫法简介
人工智能·算法·机器学习·数学建模·动态规划·图论·抽象代数
满怀冰雪2 天前
第29篇-状态压缩DP-当状态很多时如何降维优化
java·算法·动态规划
学究天人3 天前
数学公理体系大全:第一章 命题逻辑:真值之舞
人工智能·算法·机器学习·数学建模·动态规划·图论·抽象代数
旖-旎3 天前
《LeetCode 978 最长湍流子数组 || LeetCode 139 单词拆分》
c++·算法·leetcode·动态规划
学究天人3 天前
数学公理体系大全:Comprehensive Collection of Mathematical Axiom Systems(补充卷9)
人工智能·线性代数·算法·数学建模·动态规划·原型模式·抽象代数
初学者,亦行者3 天前
算法设计与分析:动态规划 - TSP问题和0-1背包问题
c++·算法·动态规划