地下城游戏解决方案解释

时间:2017-03-17 03:35:48

标签: python algorithm dynamic-programming

地下城游戏被描述为:

恶魔抓住了公主(P)并将她关进监狱 在地牢的右下角。 Ť 他的地牢包含了以2D网格布局的M x N个房间。 我们英勇的骑士(K)最初位于左上角的房间里 并且必须通过地牢来拯救公主。

骑士的初始健康点由正整数表示。 如果他的健康点在任何时候降至0或以下,他会立即死亡。

部分房间被恶魔守卫, 所以骑士进入这些房间后会失去健康(负整数); 其他房间要么是空的(0' s),要么包含增加骑士健康的魔法球(正整数)。

为了尽快到达公主, 骑士决定在每一步中只向右或向下移动。

编写一个函数来确定骑士的最低初始健康状况 这样他就能救出公主。

例如,考虑到下面的地牢,最初的健康状况 如果骑士遵循最佳路径RIGHT->,则骑士必须至少为7。右 - >向下 - > DOWN。

注意:

骑士的健康没有上限。 任何房间都可以包含威胁或加电,即使是骑士进入的第一个房间 以及公主被监禁的右下方房间。

示例:

dungeon = [[-2,  -3,  4],
           [-6, -15,  0],
           [10,  25, -6]]

答案:8

代码解决方案是:

def dungeonGame(dungeon):
    dp = [float("inf") for _ in dungeon[0]] 
    dp[-1] = 1 

    for i in reversed(range(len(dungeon))):
        dp[-1] = max(dp[-1] - dungeon[i][-1], 1)
        for j in reversed(range(len(dungeon[i]) - 1)):
            min_HP_on_exit = min(dp[j], dp[j + 1])
            dp[j] = max(min_HP_on_exit - dungeon[i][j], 1)

    return dp[0]

有人可以解释上述解决方案是如何运作的吗?为什么dp仅提供示例中的len 3?是因为只需要3个步骤,不包括开始和结束房间?为什么它在相邻的dp上达到最小值,然后达到最大值?另外,自从dungeon [i] [j]以来,最后一列似乎没有被考虑,其中j仅上升到1(采用给定的示例矩阵)。我知道解决方案写得很好,只是想了解它如何考虑所有路径。

1 个答案:

答案 0 :(得分:2)

此算法从右下方向后移动,向左然后向上,找到沿途每一步的最佳得分。我建议您使用笔和纸执行算法,记下沿途的i,j和dp的当前值。这应该真的很清楚。

  

(开始):没有我,没有j,dp = [inf inf 1]

为了获胜,你需要至少1 HP才能获胜。

  

(进入第一个循环后):i = 2,dp = [inf inf 7]。

你需要7点生命才能在右下方的-6中生存下来。

  

(进入内循环后):i = 2,j = 1,dp = [inf 1 7]

如果你位于底部中心的正方形,那么最小的1个生命值就足以在该正方形的+25上生存,并到达需要至少7的相邻正方形。依此类推。

这是在右转(存储在中间结果的下一个元素library(ggplot2) library(grid) library(gtable) p = ggplot(mpg, aes(cty, hwy, color = factor(year))) + geom_point() + facet_wrap(~ cyl, nrow = 1) gt <- ggplotGrob(p) panels = subset(gt$layout, grepl("panel", gt$layout$name), t:r) # The span of the vertical gap Bmin = min(panels$t) - 1 Bmax = max(panels$t) # The columns of the gaps (two to the right of the panels cols = unique(panels$r)[-length(unique(panels$r))] + 2 # The grob - grey rectangle g = rectGrob(gp = gpar(col = NA, fill = "grey40")) ## Add greyrectangles into the vertical gaps gt <- gtable_add_grob(gt, rep(list(g), length(cols)), t=Bmin, l=cols, b=Bmax) ## Draw it grid.newpage() grid.draw(gt) )或向下,dp[j + 1]之间选择的关键线。

dp[j]

中间结果只有三个元素,因为移动规则(仅向右和向下移动)和对角线为3的地牢,最多只有3个地方可以在任意数量的移动之后。

每当求解器向上移动一行时,最后一列将作为一个特例来处理:

min_HP_on_exit = min(dp[j], dp[j + 1])

为什么呢?嗯,它与其他专栏的不同之处在于你无法向右移动,只能向下移动。