动态规划的动态转移方程怎么寻找,实例分析

本文介绍了动态规划算法的基础概念,包括如何构建子问题和找到状态转移方程。通过一个地下城游戏的例子,展示了记忆化搜索和动态规划的解题过程。在记忆化搜索版本中,通过递归并利用缓存优化计算,而在动态规划版本中,自底向上更新状态以求解最优解。最后给出了两种方法的代码实现。
摘要由CSDN通过智能技术生成

前言

以下内容我是和左神学的,更多专业算法知识请向左神学习!

动态规划初识

动态规划算法:通过构建一系列子问题,求解部分子问题,然后通过子问题的依赖关系,求解出所有子问题,一般来说最后的那个子问题就是最终需要的答案。

公式描述就是:
构建子问题 p 1 , p 2 , p 3 , . . . p n p_{1},p_{2},p_{3},...p_{n} p1,p2,p3,...pn
求解部分子问题 p 1 p_{1} p1
状态转移 p i = f ( p i − 1 ) p_{i}=f(p_{i-1}) pi=f(pi1)
得到答案 r e s u l t = p n result=p_{n} result=pn

动态规划算法的关键就是,如何构建子问题?如何找到状态转移方程?

模板思路

暴力递归 -> 记忆化搜索 -> 动态规划

暴力递归大家应该都懂,使用暴力尝试的方法求解问题,主要是用计算机的计算思维、搜索思维解决问题。
记忆化搜索,在暴力递归的基础上加了小改进,当我们已经计算过 function(x,y)后,下次不用再计算了,直接返回结果,具体的实现方法可通过简单打表实现,计算出值就放入表,下次再需要这个值直接查表。
动态规划,通过前两部分的尝试,我们已经可以看出来动态转移方程是什么样的,动态规划是一种高度精巧的算法模型,往往会有更快的速度,更少的空间复杂度(动态规划状态表有时可优化)。

题目示例

题目描述

  1. 地下城游戏 (hard)
    一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

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

编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。

例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。

-2(K)-33
-5-101
1030-5 (P)

说明:

骑士的健康点数没有上限。

任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

解析

#记忆化搜索版本
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
    lengthx=len(dungeon)
    lengthy=len(dungeon[0])
    @lru_cache(None)  #函数修饰器,缓存,偷个懒哈哈
    def get_min_sum(x,y):
        if x==len(dungeon)-1 and y==lengthy-1:
            return dungeon[x][y]
        if x==len(dungeon)-1:
            return min(dungeon[x][y],dungeon[x][y]+ get_min_sum(x,y+1))
        if y==lengthy-1:
            return min(dungeon[x][y],dungeon[x][y]+ get_min_sum(x+1,y))
        return min(dungeon[x][y],dungeon[x][y]+max( get_min_sum(x+1,y),get_min_sum(x,y+1) ) )
    min_sum=get_min_sum(0,0)
    if min_sum>0:
        return 1
    else:
        return -min_sum+1
#动态规划版本
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
    lengthx=len(dungeon)
    lengthy=len(dungeon[0])
    for y in range(lengthy-2,-1,-1):
        dungeon[lengthx-1][y]=min( dungeon[lengthx-1][y] , dungeon[lengthx-1][y]+dungeon[lengthx-1][y+1] )
    for x in range(lengthx-2,-1,-1):
        dungeon[x][lengthy-1]=min( dungeon[x][lengthy-1] , dungeon[x][lengthy-1]+dungeon[x+1][lengthy-1] )
    for x in range(lengthx-2,-1,-1):
        for y in range(lengthy-2,-1,-1):
            dungeon[x][y]=min(dungeon[x][y],dungeon[x][y]+max(dungeon[x+1][y],dungeon[x][y+1]))
    if dungeon[0][0]>0:
        return 1
    else:
        return -dungeon[0][0]+1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会写代码的孙悟空

赠人玫瑰 手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值