题目:
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2 (K) -3 3
-5 -10 1
10 30 -5 (P)
思路:我们可以先设置dp[][]数组
dp[i][j] :代表走到这一格需要的生命值
比如:走到-5,我们至少需要1-(-5) = 6
走到30 ,我们需要 max(1,6-30) = 1,我们只要保证到30这块生命值为1 就行
走10,我们需要max(1,1-10) = 1,我们只要保证生命值为1
走1,我们需要max(1,6-1) = 5,我们要保证生命值为5,这样它走到-5时才不会死亡
走-10 ,因为10 可以走向1,和30 ,我们就找需要最少的生命值那一边。我们需要max(1,min(1,5)-(-10))= 11.
走-5,因为-5可以走向-10,10。我们就找需要最少的生命值那一边。我们需要max(1,min(1,11)-(-5))= 6.
走3,我们需要max(1,5-3) = 2,我们要保证生命值为2
走-3,因为-3可以走向-10,3。我们就找需要最少的生命值那一边。我们需要max(1,min(2,11)-(-3))= 5.我们需要5
最后到-2 ,因为-2可以走向-3,-5。我们就找需要最少的生命值那一边。我们需要max(1,min(6,5)-(-2))= 7,我们需要7
代码:
public class Test174 {
public static void main(String[] args) {
int[][] dungeon = {
{0,0},
};
System.out.println(calculateMinimumHP(dungeon));
}
public static int calculateMinimumHP(int[][] dungeon) {
if(dungeon.length == 0){
return 0;
}
int[][] dp = new int[dungeon.length][dungeon[0].length];
int min = 0;
for(int i = dp.length-1;i >= 0;i--) {
for(int j = dp[i].length-1;j >= 0;j--) {
if(i == dp.length-1 && j == dp[i].length-1){
min = 1;
dp[i][j] = Math.max(1,min-dungeon[i][j]);
}else if(i == dp.length-1 && j != dp[i].length-1){
min = dp[i][j+1];
dp[i][j] = Math.max(1,min-dungeon[i][j]);
}else if(i != dp.length-1 && j == dp[i].length-1){
min = dp[i+1][j];
dp[i][j] = Math.max(1,min-dungeon[i][j]);
}else {
min = Math.min(dp[i+1][j] , dp[i][j+1]);
dp[i][j] = Math.max(1,min-dungeon[i][j]);
}
}
}
return dp[0][0];
}
}