动态规划(用空间换时间的算法)原理逻辑代码超详细!参考自《算法导论》

这篇具有很好参考价值的文章主要介绍了动态规划(用空间换时间的算法)原理逻辑代码超详细!参考自《算法导论》。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本篇博客以《算法导论》第15章动态规划算法为本背景,大量引用书中内容和实例,并根据书中伪代码给出python代码复现,详解算法的核心逻辑和实现过程。

动态规划(DP)思想

动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为重叠的子问题进行解决,从而一步步获取最优解的处理算法。

动态规划与分治方法相似,都是通过组合子问题的解来求解原问题(在这里“programming”指的是一种表格法,并非编写计算机序)。但是分治方法将问题划分为互不相交的子问题,递归地求解子问题,再将它们的解组合起来,求出原问题的解。与之相反,动态规划应用于子问题重叠的情况,即不同的子问题具有公共的子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。

在这种情况下,分治算法会做许多不必要的工作,它会反复地求解那些公共子子问题。而动态规划算法对每个子子问题只求解一次,将其解保存在一个表格中,从而无需每次求解一个子子问题时都重新计算,避免了这种不必要的计算工作。

实例说明

动态规划方法常用来求解最优化问题,下面分别给出二个例子来说明:第一个是将钢条割成短钢条,使得总价值最高;第二个是解决如何用最少的标量乘法操作完成一个矩阵链相乘的运算

钢条切割问题

下面是钢条切割问题的背景:

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
比如,下图给出长度为4英寸钢条所有可能的切割方案:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
其中,钢条上方的数字为每段钢条对应的价格。不同的切割方案对应不同的价格,我们发现,将一段长度为4英寸的钢条切为两段各长2英寸的钢条,将产生 P 2 P_2 P2+ P 2 P_2 P2=5+5=10的收益,为最优解,即对应上图中的方案C。

下面我们逐步分析出钢条切割问题的最优收益的递推公式:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
更为一般的收益公式,长度为n的钢条切割后的最大收益 r n r_n rn表示如下:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
一种更简单的递归方法:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
其中,(15.2)式中的 p i p_i pi指长度为i的钢条对应的价格,直接查表得到,不用再进行切割。

如果用传统的递归方法求解,一旦n的规模稍微变大,程序运行的时间会变得相当长,因为这种方法反复用相同的参数值对自身进行递归调用,即它反复求解相同的子问题。时间呈指数级增长。下图给出n=4时,递归树的调用过程:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划方法的运行时间是多项式阶的。
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划有两种等价的实现方法:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
下面给出自底向上法的代码实现过程:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
在上面的伪代码中,输入为两个变量,价格表数组和长度n;输出长度为n的钢条得到的最优收益。

下面计算长度为9时,钢条切割的最大收益:

import numpy as np

def Bottom_Up_Cut_Rod(p, n):
    r = []
    r.insert(0, 0)
    for j in range(1, n + 1):
        q = float('-inf')
        for i in range(1, j + 1):
            q = max(q, p[i - 1] + r[j - i])
        r.insert(j, q)
    return r[n]

if __name__ == '__main__':
    # 出售长度为i(i=1,2,3,,,10)的钢条所对应的价格样表
    p = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
    n = 9
    result = Bottom_Up_Cut_Rod(p, n)
    print("长度为{}时,".format(n))
    print("对应的最优收益值为{}。".format(result))

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
下图是长度为1、2、3…,对应的最优切割方案和收益。
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法

思想:为了求解规模为 n 的原问题,我们先求解形式完全一样,但规模更小的子问题。即当完成首次切割后,我们将两段钢条看成两个独立的钢条切割问题实例。我们通过组合两个相关子问题的最优解,并在所有可能的两段切割方案中选取组合收益最大者,构成原问题的最优解。

我们称钢条切割问题满足最优子结构性质:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。

矩阵链乘法问题

矩阵链乘法问题即是多个矩阵相乘,找出最快计算次序的问题。

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法

对矩阵链加括号的方式会对乘积运算的代价产生巨大影响,下面举例来说明:

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
因此,如果A是pXq的矩阵,B是qXr的矩阵,那么乘积 C是pXr的矩阵。计算 C所需时间由标量乘法的次数决定,即 pqr。下面我们将用标量乘法的次数来表示计算代价

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法

传统方法:穷举所有可能的括号化方案不会是一个高效的算法,因为它的运行时间仍然是指数级增长的。

下面定义矩阵链问题的计算代价公式,令m[i,j]表示计算矩阵 A i , . . . , j A_{i,...,j} Ai,...,j所需标量乘法次数的最小值。

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
假设最优分割点k是未知的,则递归求解公式变为:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
下面用一个例子来说明:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
上图是我手写的一个例子,为了帮助理解。其中, A 1 A_1 A1:2 × \times × 3 ,表示 A 1 A_1 A1的维度为2行3列,P列表存放的是四个矩阵的维度,其中前一个矩阵的列数等于后一个矩阵的行数。要求出 A 1 A_1 A1 A 2 A_2 A2 A 3 A_3 A3 A 4 A_4 A4的计算代价,假设分割点k=2,则计算顺序为 ( ( A 1 A 2 ) ( A 3 A 4 ) ) ((A_1A_2)(A_3A_4)) ((A1A2)(A3A4))。其中, ( A 1 A 2 ) (A_1A_2) (A1A2)的计算代价对应上图中的矩阵C, ( A 3 A 4 ) (A_3A_4) (A3A4)的计算代价对应上图中的矩阵D,最后再令C与D相乘,算的最后的计算代价(总次数)为48。

下面给出的过程 MATRIX-CHAIN-ORDER实现了自底向上表格法:
各输入变量的含义如下:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
输出变量为最优代价矩阵m和最优分割点矩阵k。

下面给出代码的计算过程帮助理解。假设n=4, p = [ p 0 , p 1 , p 2 , p 3 , p 4 ] p = [p_0,p_1,p_2,p_3,p_4] p=[p0,p1,p2,p3,p4],求 A 1 A 2 A 3 A 4 A_1A_2A_3A_4 A1A2A3A4的最优代价,即求m[1,4]。计算过程如下:
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法

左边是最优代价矩阵,右边是最优分割点矩阵

以图15-5的数据为例,python代码如下:

import numpy as np

def MATRIX_CHAIN_ORDER(p):
    n = len(p) - 1
    # 定义计算代价矩阵m
    m = np.zeros((n, n))
    # 定义最优分割点矩阵s
    s = np.zeros((n, n))
    for l in range(2, n + 1):
        for i in range(1, n - l + 2):
            j = i + l - 1
            m[i - 1, j - 1] = float('inf')
            for k in range(i, j):
                q = m[i - 1, k - 1] + m[k, j - 1] + p[i - 1] * p[k] * p[j]
                if q < m[i - 1, j - 1]:
                    m[i - 1, j - 1] = q
                    s[i - 1, j - 1] = k
    print(m)  # 每个元素对应长度为j-i+1的矩阵所需要最小计算代价
    print(s)  # 对应长度为j-i+1的矩阵最优分割点
    return m, s

if __name__ == '__main__':
    p = [30, 35, 15, 5, 10, 20, 25]
    MATRIX_CHAIN_ORDER(p)

运行结果如下:

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
能够看出,跑出的结果与书上的两个矩阵完全相同。(只不过书中对矩阵沿主对角线方向进行了旋转)

思路:一个非平凡的矩阵链乘法问题实例的任何解都需要划分链,而任何最优解都是由子问题实例的最优解构成的。因此,为了构造一个矩阵链乘法问题实例的最优解,我们可以将问题划分为两个子问题( A i A i + 1 ⋅ ⋅ ⋅ A k A_iA_{i+1}···A_k AiAi+1⋅⋅⋅Ak A k + 1 ⋅ ⋅ ⋅ A j A_{k+1}···A_j Ak+1⋅⋅⋅Aj)子题实例的最优解,然后将子问题的最优解组合起来。我们必须保证在确定分割点时,已经考察了所有可能的划分点,这样就可以保证不会遗漏最优解。

应用满足的条件和场景

应用动态规划方法求解的最优化问题应该具备的两个要素:最优子结构子问题重叠

动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法
动态规划,空间换时间,算法,动态规划,python,人工智能,性能优化,动态规划算法

动态规划算法可以用来求解最优化问题,除了本文给出的两个例子外,常用的场景包括求解斐波那契数列,求解最长公共子序列、01背包问题和最优二叉搜索树等。想要深入了解该算法的原理和应用场景,具体可以阅读《算法导论》,我有电子版的,需要的兄弟姐妹可以私信我取。

综上所述,满足最优子结构和子问题重叠性质的问题可以利用动态规划思想建模,这种方法会开辟内存,存储以往的运算结果,再下次遇到时直接调用而不再重复计算,因此大大节省了时间,是一种经典的用空间换时间的算法,而大多数情况下,项目对时间的要求往往更严格,相比对内存的占用情况就宽松很多了。文章来源地址https://www.toymoban.com/news/detail-794097.html

到了这里,关于动态规划(用空间换时间的算法)原理逻辑代码超详细!参考自《算法导论》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划:0-1背包、完全背包问题 | 详细原理解释 | 代码及优化(C++)

    目录 01背包 问题描述: 简单描述就是: 解析: 递推公式: dp数组的初始化: 遍历顺序: 图解: 实现代码: dp数组初始化: 遍历: 优化: 原理: 递推公式: 遍历顺序: 实现代码: 初始化: 遍历: 完全背包 问题描述: 解析: 实现代码:         01背包是在M件物品

    2024年02月11日
    浏览(37)
  • 【算法】一文带你快速入门动态规划算法以及动规中的空间优化

    君兮_的个人主页 即使走的再远,也勿忘启程时的初心 C/C++ 游戏开发 Hello,米娜桑们,这里是君兮_,如果给算法的难度和复杂度排一个排名,那么动态规划算法一定名列前茅。在最开始没有什么整体的方法的时候,我也曾经被动态规划折磨过很长时间,通过我一段时间的刷题

    2024年02月05日
    浏览(45)
  • Apollo星火计划学习笔记——Apollo开放空间规划算法原理与实践

    Apollo星火计划课程链接如下 星火计划2.0基础课:https://apollo.baidu.com/community/online-course/2 星火计划2.0专项课:https://apollo.baidu.com/community/online-course/12     开放空间算法的配置主要在 valet_parking_config.pb.txt 中,分为4个部分: OPEN_SPACE_ROI_DECIDER 、 OPEN_SPACE_TRAJECTORY_PROVIDER 、 OPE

    2023年04月10日
    浏览(40)
  • 了解动态规划算法:原理、实现和优化指南

    动态规划(Dynamic Programming,简称 DP)是一种通过将原问题拆分成子问题并分别求解这些子问题来解决复杂问题的算法思想。 它通常用于求解优化问题,它的核心思想是将原问题分解成一系列的子问题,通过找到子问题之间的递推关系,可以避免重复计算,从而大幅提高计算

    2024年02月11日
    浏览(38)
  • 深度剖析动态规划算法:原理、优势与实战

    动态规划是一种优化技术,通常用于解决那些可以分解为子问题的问题。它的核心思想是将大问题分解成小问题,通过解决小问题来构建大问题的解。这种方法通常用于解决最优化问题,其中目标是找到最佳解决方案,通常是最大化或最小化某个值。 动态规划算法的核心原理

    2024年02月07日
    浏览(44)
  • 【Matlab】动态规划算法代码记录

    简单记录一下学习Matlab过程中的代码。 参考资料:0-1背包问题 参考资料:清华学霸总结的动态规划4步曲,仅这篇动归够了

    2024年02月16日
    浏览(40)
  • 【数据结构】算法的时间复杂度和空间复杂度(含代码分析)

    如何衡量一个算法的好坏呢?比如对于以下斐波那契数列: 这里的时间复杂度为: 2^N ,计算方法请看下文。 算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复

    2024年02月05日
    浏览(60)
  • 【算法】动态规划 ⑦ ( LeetCode 55. 跳跃游戏 | 算法分析 | 代码示例 )

    LeetCode 55. 跳跃游戏 : https://leetcode.cn/problems/jump-game/ 给定一个 非负整数数组 nums ,你最初位于数组的 第一个下标 0 位置 。 数组中的每个元素 代表你在该位置可以 跳跃的最大长度。 判断你 是否能够到达最后一个下标。 给定一个一维数组 , 数组元素不能有负数 , 如 : {2, 2,

    2024年02月10日
    浏览(39)
  • 动态规划2:算法考试矩阵连乘问题(超详细手写过程)

                                      更多期末复习笔记欢迎访问我的博客: Miuuu · 语雀​​​​​​​ 动态规划理论基础:(6条消息) 动态规划1:动态规划的入门初学理论基础_黑色柳丁Angel的博客-CSDN博客 矩阵连乘问题是我在算法课接触的第一个动态规划问题

    2023年04月08日
    浏览(40)
  • 代码随想录算法训练51 | 动态规划part12

    本题加了一个冷冻期,状态就多了,有点难度,大家要把各个状态分清,思路才能清晰  视频讲解: 动态规划来决定最佳时机,这次有冷冻期!| LeetCode:309.买卖股票的最佳时机含冷冻期_哔哩哔哩_bilibili 代码随想录 相对122.买卖股票的最佳时机II ,本题只需要在计算卖出操

    2024年01月18日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包