Dungeon Game

来源:互联网 发布:软件著作权查询网站 编辑:程序博客网 时间:2024/05/29 15:32


The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.


Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

-2 (K)-33-5-1011030-5 (P)

Notes:

  • The knight's health has no upper bound.
  • Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

题目的大意是给出每个格消耗的血量或增加的血量,求从左上角走到右下角需要的最少血量。

需要注意的是骑士的血量只要比1小就会马上死亡,所以我们不能只保证骑士到达右下角时的血量大于0,因为他可能在前面某一步时血量就小于1而死亡了。

这道题目显然是要使用动态规划的,我一开始的想法是用一个二维数组,计录从左上角走到当前点需要的血量。但是这时候就会有一个问题,当我们在处理一个点时,他可以从上面的那个点走到这里,或者从左边的点走到这里,如果一条路需要的血量更少,另一条路能够使得当前能够获得更大的血量,这时候我们不能判断这两条路哪条比较好,所以这种方法是行不通的。

所以我采用的方法是和上面的方法相反,是从右下角的点往前面扫,用两个二维数组,min,cur分别记录从当前点走到终点需要的血量和当前的血量。由于在处理一个点时需要考虑的情况比较多,所以处理起来是比较复杂的,首先我们要保证骑士能够进入这个点,也就是说要保证骑士刚进入这个点时至少有1个血量,所以我用变量t记录确保骑士能够进入这个点需要的血量,然后选择向下走还是向右走,这时候就要比较它下面的点和右边的点到达终点需要的血量,也就是比较min在对应点的值,选择需要血量少的点。选择了方向以后就要计算当前的血量,因为要计算从该点走到终点的最小血量,所以我们要把骑士的当前血量控制在1这个最小值,所以我用变量add记录需要增加的血量,如果本来血量是大于1的,则add的值是负值,然后根据add的值调整需要的血量和当前血量两个值。这样一个节点就处理完了。

上面的方法需要两个二维数组,但是我们扫描数组的方向是从右到左,从下到上,而我们在处理一个节点时需要使用到的只是它下面或者右边的值,所以只使用两个一维数组就足够了。

有一点要特别注意的是,题目要求骑士在进入格子之前就要有1个血量以上,所以在返回结果之前要特判一下,如果结果为0,就要把返回的结果改为1.

程序中有一个二重循环,用到了两个大小为n的数组,所以时间复杂度为O(m*n),空间复杂度为O(n)。

以下为源代码:

class Solution {public:    int calculateMinimumHP(vector<vector<int>>& dungeon) {        int m=dungeon.size();        int n=dungeon[0].size();        vector<int> cur(n,0),min(n,10000000);        min[n-1]=max(0,1-dungeon[m-1][n-1]);        cur[n-1]=min[n-1]+dungeon[m-1][n-1];        for(int i=m-1;i>=0;i--)            for(int j=n-1;j>=0;j--)            {                if(i==m-1&&j==n-1) continue;                int t=0;                if(dungeon[i][j]<=0) t=-dungeon[i][j]+1;                if(j<n-1&&min[j+1]<min[j])                {                    cur[j]=cur[j+1]+dungeon[i][j];                    int add=-cur[j]+1;                    min[j]=max(t,min[j+1]+add);                    cur[j]+=add;                }                else                {                    cur[j]=cur[j]+dungeon[i][j];                    int add=-cur[j]+1;                    min[j]=max(t,min[j]+add);                    cur[j]+=add;                }            }        if(min[0]==0) return 1;        else return min[0];    }};

0 0