算法导论动态规划15.1总结

本文深入探讨动态规划的概念,通过对比分治法解释动态规划的特点,以钢管切割问题为例,详细阐述动态规划的最优子结构、递归方案、时间复杂度和空间优化。同时介绍了动态规划的两种实现方法:带备忘的自顶向下和自底向上,并展示了扩展动态规划以返回解本身。最后提出了一个问题:如何返回多组不同的最优解。
摘要由CSDN通过智能技术生成

动态规划是将复杂的问题分成数个简单的子问题,然后再去解决。它们的区别在于,分治法关注的子问题不相互“重叠”,而动态规划关注的子问题,多是相互“重叠”的。不同子问题具有公共的子子问题的求解也是递归进行,将其划分为更小的子子问题。

比如在快速排序中,我们将数据分成两部分,这两部分再分别快速排序的递归思想,也就是将整个问题的排序划分为子问题子数组的排序,但是这两个子数组的排序之间并没有相互联系,a子数组的排序不会因为b子数组的排序而得到任何“好处”或者“坏处”。
动态规划运用表格方法通过组合子问题的解来进行求解原问题,动态规划不同于分治法,分治法产生大量重复计算,而动态规划仅仅是每个子子问题求解一次,保存在一个表格当中,避免大量重复计算。

钢管切割问题:
问题核心:有一段长度为i的钢管,整段出售的价格为Pi,求适当的切割钢条方案使得获利最大
在这里插入图片描述
收益
Rmax=Pi1+Pi2+Pi3+Pi4+······Pik
我们讲长度为i的钢管生成切割成为k段,每段的最大利益为Pik
钢管的切割问题满足最优子结构:问题的最优解由相关子问题的最优解组合而成,这些问题时可以独立求解
我们进行一个更加一般化的描述:

在这里插入图片描述
进而
具体证明方法就是反正法:假设Pi1,Pi2,Pi3段切割方案使得Rmax最大,如果Pi2+Pi3不是最大,那么就可以找到另外一种切割方法,使得Rmax也不可能为最大,所以无论你最终结果切割多少段,你都可以先分为两端。这就是最优子结构的关键,大问题的最优解一定由小问题的最优解组合构成。
进而
在这里插入图片描述
直观考虑递归方案:

#include <bits/stdc++.h>
using namespace std;
int p[11]={
   0,1, 5, 8, 9, 10, 17, 17, 20, 24, 30};//储存钢管长度售价信息,长度为i+1的钢管的价值
int CUT_ROD(int p[] ,int length);
int main()
{
   
cout<<CUT_ROD(p,10)<<endl;
return 0;
}
int CUT_ROD(int p[] ,int length ) //自顶向下递归实现
{
   
if(length==0) return 0;
int Rmax=0;
for(int i=1;i<=length;i++)
          Rmax=max(Rmax,p[i]+CUT_ROD(p,length-i));//i=1 to length 每个问题都可以分为两个问题的最优解
return Rmax;
}

递归返回调用自身去计算每一个子问题,即使子问题被计算过了,也要大量计算
在这里插入图片描述
在这里插入图片描述
从父节点s到子节点的边表示从钢条左端切下长度为s-t的一段,然后继续继续递归求解剩余规模为t的子问题,一般来说递归调用树共有2n个结点,其中2n-1个叶结点,所以时间复杂度为T(2n)

动态规划的好处就是每个子问题求解一次,将其保存,付出额外的内存空间来节省计算时间,典型的时空权衡案例,时间上节省巨大将一个指数级别的时间转化为了一个多项式的时间。
如果子问题的数量是输入规模的多项式的函数,我们在多项式的时间内求解出每一个子问题,动态规划总运行时间是多阶。

单纯的递归可以转化为带备忘的自顶向下的递归方法:

int store[11]={
   0};//申明一个数组来储存最优解
int MEMOIZED_CUT_ROD_AUX(int p[], int length)
{
   
    if(store[length]!=0)         return store[length];
   if(length==0) return 0;
   int Rmax=0;
    for(int i=1;i<=length;i++)
          Rmax=max(Rmax
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值