LeetCode | Dungeon Game

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 least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

-2 (K) -3 3
-5 -10 1
10 30 -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.

参考博文:http://blog.csdn.net/ljiabin/article/details/42616291
这个是原地操作,强… http://www.cnblogs.com/easonliu/p/4237644.html
这个题目和之前的Minimun Path Sum不太一样,导致一开始直接看岔了…
题目要求骑士在到达公主的格子之前,生命值不能归零。
一开始我尝试了先走出路径,然后根据dp矩阵逆推回去的思路….然后发现了我思路的问题
3  -20  30
-3   4    0
于是按照最大价值走下去会走到3->-20->30->0;这样造成需要很大的血量来应付中间的-20,实际上这条路不是所希望的最优的。
所以,要寻找的是从起点开始,所遇到的路径中血量最低值最大的。
思考正向推导的话,似乎不能很好地得到答案。
考虑从终点开始往前推
dp[i][j]表示从座标(i, j)到右下角所需的血量。初始化时假设最后剩余血里为max(-dp[m-1][n-1],0)血量

意思是,从[m-1,n-1]到[m-1,n-1]至少需要-dp[m-1][n-1]才不至于归零。
例如只有一个元素[[-100]],则进入起点不归零的至少100
如果是[[100]],则至少需要0
这样一来每往前推一步,需要考虑min(dp[i][j+1],dp[i+1][j])-dp[i][j]的大小,这表示从[i][j]经i+1或者j+1到右下角所需要的血量,即二者最大+当前格子所需血量。
由于我们需要的是最小的血量,需要做一步max(val,0)其中val是[i][j]的值。因为如果血量过大是没有意义的,我们需要的是最少的值。
这样一来就可以得到DP方程dp[i][j]=max(min(dp[i][j+1],dp[i+1][j])-dp[i][j],0)
非常重要的一点是可以原地操作,仔细想想即可想通。

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) {
        int m=dungeon.size();
        int n=dungeon[0].size();
        
        //不是走最多的那一条,而是路径上的最小值最大的那一条,即且最小值>0
        //可以原地操作
        dungeon[m-1][n-1]=max(-dungeon[m-1][n-1],0);
        for(int j=n-2;j>=0;j--) dungeon[m-1][j]=max(dungeon[m-1][j+1]-dungeon[m-1][j],0);
        for(int i=m-2;i>=0;i--) dungeon[i][n-1]=max(dungeon[i+1][n-1]-dungeon[i][n-1],0);
        
        for(int i=m-2;i>=0;i--){
            for(int j=n-2;j>=0;j--){
                dungeon[i][j]=max(min(dungeon[i+1][j],dungeon[i][j+1])-dungeon[i][j],0);
            }
        }
        return dungeon[0][0]+1;
        // int dp[m+1][n+1];
        // memset(dp,0,sizeof(dp));
        // dp[m-1][n-1]=dungeon[m-1][n-1];
        // for(int j=n-2;j>=0;j--) dp[m-1][j]=dp[m-1][j+1]+dungeon[m-1][j];
        // for(int i=m-2;i>=0;i--) dp[i][n-1]=dp[i+1][n-1]+dungeon[i][n-1];
        // //得到dp数组
        // for(int i=m-2;i>=0;i--){
        //     for(int j=n-2;j>=0;j--){
        //         dp[i][j]=max(dp[i+1][j],dp[i][j+1])+dungeon[i][j];
        //     }
        // }
        
        // printf("val %d\n",dp[m-1][n-1]);
        // return dp[0][0]>0?1:-dp[0][0]+1;
    }
    
    //直接按照原来的dp未必是最优的路径
    //[[3,-20,30],[-3,4,0]]
    // void comeBack(int x,int y,int total,int& minV,int dp[][1000],vector<vector<int>>& dungeon){
    //     //递归终点
    //     if(x==0 && y==0){
    //         //存储最小值
    //         minV=minValue(minV,dp[x][y],dungeon[x][y]);
    //         return;
    //     }
    //     else minV=min(minV,dp[x][y]);
        
    //     //判断是否越界
    //     if(x-1>=0 && dp[x-1][y]==dp[x][y]-dungeon[x][y])
    //     comeBack(x-1,y,total,minV,dp,dungeon);
        
    //     if(y-1>=0 && dp[x][y-1]==dp[x][y]-dungeon[x][y])
    //     comeBack(x,y-1,total,minV,dp,dungeon);
    // }
    
    // int minValue(int a,int b,int c){
    //     int d=a>b?b:a;
    //     return d>c?c:d;
    // }
};




点赞