174. 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 (positiveintegers).

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.
 
 
这道题的dp是倒序的,这点很重要,为什么不能像【最小路径和】一样是正序的?因为【最小路径和】是无状态的,你会发现【最小路径和】倒序dp也是可以的,这道题由于有“加血”的过程,只能依赖后面的值判断需要的血量。所以这里的dp[i][j]表达的意思是:“从(i,j)出发,到达终点需要最少的血量”。因此,正序的含义为“从起点出发,到达位置(i,j)所需要的最少血量”;倒序的含义是“从(i,j)出发,到达终点需要最少的血量”。初始血量本来就是要求的,所以只能倒序dp
 
class Solution:
    def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
        #倒序的含义是“从(i,j)出发,到达终点需要最少的血量
        m = len(dungeon)
        n = len(dungeon[0])
        dp = [[0] * n for _ in range(m)]
        dp[m-1][n-1] = max(0,-dungeon[m-1][n-1])
        for i in range(0,m-1)[::-1]:
            dp[i][n-1]=max(dp[i+1][n-1]-dungeon[i][n-1],0)
        for j in range(0,n-1)[::-1]:
            dp[m-1][j]=max(dp[m-1][j+1]-dungeon[m-1][j],0)
        for i in range(0,m-1)[::-1]:
            for j in range(0,n-1)[::-1]:
                #从右边和下边选择一个最小值,然后减去当前的 dungeon 值 
                need_min = min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j]
                dp[i][j] = max(need_min,0)    
        return dp[0][0]+1

 

posted @ 2018-05-05 23:40  乐乐章  阅读(287)  评论(0编辑  收藏  举报