(Version 0.0)

应该说这是一道入门级的典型DP题目,因为可以较为明显地看出进入当前考虑的格子需要的HP值依赖于在进入这个格子之后往哪个方向走,也就是说依赖于进入当前格子的下方格子和右边格子所需要的HP值的最小可能值。这样一来我们可以把子问题抽象成:如果整个dungeon的左上角是当前在考虑的格子,最终目标是救出最右下角的公主,求所需要的初始HP值的可能最小值。

在代码实现中,如果用一个二维数组中的元素require[i][j]来维护进入dungeon[i][j]所需的最小HP值,则状态转移关系为:require[i][j] = dungeon[i][j] >= minRequire ? 1 : minRequire - dungeon[i][j],其中minRequire是进入dungeon[i + 1][j]和dungeon[i][j + 1]所需的HP值中较小的那个。也就是说,如果dungeon[i][j]可以满足进入下一个格子(右边的或者下边的格子),那么进入dungeon[i][j]的条件仅仅是你还活着,即HP值为1(其实有一种情况下即使dungeon[i][j]比进入下一格子需要的最小值还小也可以,即dungeon[i][j] = minRequire - 1,因为你进入dungeon[i][j]时是自带1点的HP的,所以少1也可以,不过这种情况其实与后面要说的情况在代码求解上是一样的,所以为了代码简短,在实现上就归类到后面一种去了);如果dungeon[i][j]不能满足进入下一个格子,那么进入dungeon[i][j]的条件就是你在进入dungeon[i][j]前的HP值必须至少也能解决掉经过dungeon[i][j]补给之后继续往后走的HP需求,即minRequire - dungeon[i][j]。代码如下:

 

 1 public class Solution {
 2     public int calculateMinimumHP(int[][] dungeon) {
 3         int[][] require = new int[dungeon.length][dungeon[0].length];
 4         int buttom = dungeon.length - 1;
 5         int right = dungeon[0].length - 1;
 6         require[buttom][right] = dungeon[buttom][right] >= 0 ? 1 : 1 - dungeon[buttom][right];
 7         for (int i = dungeon[0].length - 2; i >= 0; i--) {
 8             require[buttom][i] = dungeon[buttom][i] >= require[buttom][i + 1] ? 1 : require[buttom][i + 1] - dungeon[buttom][i];
 9         }
10         for (int i = dungeon.length - 2; i >= 0; i--) {
11             require[i][right] = dungeon[i][right] >= require[i + 1][right] ? 1 : require[i + 1][right] - dungeon[i][right];
12         }
13         for (int i = dungeon.length - 2; i >= 0; i--) {
14             for (int j = dungeon[0].length - 2; j >= 0; j--) {
15                 int minRequire = Math.min(require[i + 1][j], require[i][j + 1]);
16                 require[i][j] = dungeon[i][j] >= minRequire ? 1 : minRequire - dungeon[i][j];
17             }
18         }
19         return require[0][0];
20     }
21 }

 

总体而言,这是一道比较中规中矩的动态规划题目,其中子问题的定义比较直接,optimal substructure也比较明显地可以看到,个人感觉比较适合动态规划入门水平的练习。

posted on 2015-03-18 12:08  _icecream  阅读(152)  评论(0编辑  收藏  举报