LeetCode 174. Dungeon Game 逆序动态规划

231 篇文章 0 订阅
120 篇文章 1 订阅

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 (negativeintegers) 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)-33
-5-101
1030-5 (P)

 

Note:

  • 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. 这个路径不对称,假设K和P的位置颠倒,结果完全不一样,很容易举例子

2. 假设从左上出发,到达(i,j)时,有两个状态,一是这条路径上最大的分、二是当前的分,从(i,j)到(i+1,j)或者(i,j+1)时,这两个分可能在这两个方向上都刷新,状态急剧增多,脑子进入大坑。。。

针对2采用逆向思维的方式,假设dp[i][j]表示到达前(i,j)最少体力值是多少,那么从dp[rows-1][cols-1]开始逆向递推。。。after表示被这格子消耗后至少要保留多少体力,才够满足下游的消耗,当然after >= 1,所以从下游向上游dp[i][j]反推:

from typing import List

class Solution:
    def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
        rows,cols = len(dungeon),len(dungeon[0]) if dungeon else 0
        dp = [[0 for j in cols] for i in rows]
        if rows == 0 or cols == 0:
            return 0
        for i in range(rows)[::-1]:
            for j in range(cols)[::-1]:
                after = 1
                if (i == rows-1 and j == cols-1):
                    after = 1
                elif (i == rows-1):
                    after = dp[i][j+1]
                elif (j == cols-1):
                    after = dp[i+1][j]
                else:
                    after = min(dp[i][j+1],dp[i+1][j])
                #after表示被(i,j)位置的格子消耗后至少要保留多少体力(当然after>=1),才够下游继续消耗,然后向上游反推
                if (after <= dungeon[i][j]):
                    dp[i][j] = 1
                elif (dungeon[i][j] < 0):
                    dp[i][j] = after-dungeon[i][j]
                else:
                    dp[i][j] = after-dungeon[i][j]
        return dp[0][0]

s = Solution()
print(s.calculateMinimumHP([[-1,1]]))
print(s.calculateMinimumHP([[-2,-3,3],
                            [-5,-10,1],
                            [10,30,-5]]))

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值