【网格 dp】A007_LC_地下城游戏(讨论最少健康值)

一、Problem

一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

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

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

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

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

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
【网格 dp】A007_LC_地下城游戏(讨论最少健康值)_第1张图片
说明:

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

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

二、Solution

方法一:记忆化

利用 dp 的思想,递归地搜索答案,dfs(i, j) 返回的是你从 (i-1, j) 或 (i, j-1) 走到 (i, j) 所需要的最少健康值

比如从某一格到达最后一格 (n-1, m-1) 时:

  • 如果 g[n-1][m-1] < 0,那你至少需要 1-g[n-1][m-1] 吧;
  • 否则你在上一格的位置的健康值至少为 1(因为健康值不能低于 1)

基于上面这两点逻辑,很容易推广到一般的点

class Solution {
public:
	int n, m;
	vector<vector<int>>& g;
	int dfs(int i, int j, vector<vector<int>>& f) {
        if (i == n-1 && j == m-1) {
            return max(1-g[i][j], 1);
        }
        if (f[i][j] != 0) return f[i][j];
        if (i == n-1)     return max(dfs(i, j+1, f)-g[i][j], 1);
        if (j == m-1)     return max(dfs(i+1, j, f)-g[i][j], 1);
        int d = dfs(i+1, j, f), r = dfs(i, j+1, f), mi = min(d, r);
        return f[i][j] = max(mi-g[i][j], 1);
    }
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
    	g = dungeon;
        n = g.size(), m = g[0].size();
        vector<vector<int>> f(n, vector<int>(m));
    	return dfs(0, 0, f);
    }
};

复杂度分析

  • 时间复杂度: O ( n × m ) O(n × m) O(n×m)
  • 空间复杂度: O ( n × m ) O(n × m) O(n×m)

你可能感兴趣的:(#,网格,dp)