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];
    }
};
相关推荐
UIU11415 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
木井巳2 天前
【动态规划: 路径问题】下降路径最小和
java·算法·leetcode·动态规划·推荐算法
YLCHUP2 天前
【模拟&STL】题解:AT_abc203_e [ABC203E] White Pawn_基础算法_数据结构_STL模板库_AtcoderABC_C++算法竞赛
数据结构·c++·算法·leetcode·动态规划·哈希算法·近邻算法
INGNIGHT4 天前
440 · 背包问题(三)(无限次数)
算法·leetcode·动态规划
木井巳5 天前
【动态规划: 路径问题】不同路径
java·算法·leetcode·动态规划
basketball6166 天前
动态规划第一章:引论
算法·动态规划·1024程序员节
木井巳6 天前
【动态规划: 线性dp】解码方法
java·算法·leetcode·动态规划·推荐算法
stolentime7 天前
SOS DP学习笔记
c++·笔记·学习·算法·贪心算法·动态规划·二进制
y1su8 天前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划