钢条切割问题

1. 问题

某公司出售钢条,出售价格与钢条长度之间的关系如下表:
问题:现有一段长度为n的钢条和上面的价格表,求切割钢条方案,使得总收益最大。

2. 思路

思考: 长度为n的钢条的不同切割方案有几种?
有2n−12^{n-1}2n−1种,因为有n−1n-1n−1个可以切割的地方,每个位置都有切与不切两种选择,所以是2n−12^{n-1}2n−1种,但是这种方法不太合适,因为如果n太大的时候,切割方案会指数爆炸,效率不高

2.1 最优子结构

昨天有讲动态规划,动态规划(DP)的思想 = 最优子结构(递推式) + 重复子问题,那么我们可以看看这道题目的最优子结构:

  1. 可以将求解规模为n的原问题,划分为规模更小的子问题:完成一次切割后,可以将产生的两段钢条看成两个独立的钢条切个问题。
  2. 组合两个子问题的最优解,并在所有可能的两段切割方案中选取组合收益最大的,构成原问题的最优解。
  3. 钢条切割满足最优子结构:问题的最优解由相关子问题的最优解组合而成,这些子问题可以独立求解。

最优子结构(大的问题切割为小的子问题,如果子问题有最优解并且这些最优解解能算大问题的解,即最优子结构)

2.2 递推式

我们再来看看这道问题的递推式:
设长度为n的钢条切割后最优收益值为rn,可以得出递推式:
rn=max(pn,r1+rn−1,r2+rn−2,...,rn−1十r1)r_n=max(p_n,r_1 +r_{n-1},r_2+r_{n-2},...,r_{n-1}十r_1)rn​=max(pn​,r1​+rn−1​,r2​+rn−2​,...,rn−1​十r1​)
第一个参数pnp_npn​表示不切割,其他n−1n-1n−1个参数分别表示另外n−1n-1n−1种不同切割方案,对方案i=1,2...n−1i=1,2...n-1i=1,2...n−1,将钢条切割为长度为iii和n−in-in−i两段,方案i的收益为切割两段的最优收益之和,考察所有的iii,选择其中收益最大的方案!

3. 代码

从递推式,我们想到可以用递归求解!有结束条件,又是调用自身

'''
TOPIC: 钢条切割: 递归实现
author: Blue
time: 2020-08-19
QQ: 2458682080
'''# 价格列表,下标即为长度
p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30]def cut_rod_recurision_1(p, n):if n == 0:return 0else:res = p[n]for i in range(1, n):res = max(res, cut_rod_recurision_1(p, i) + cut_rod_recurision_1(p, n - i))# 递归2次,所以慢return res
print(cut_rod_recurision_1(p, 10))

结果为: 30,即当钢条长度n=10时,最大总收益为30!

4. 思路改进

昨天的博客里说到了,当n变大时,递归的效率其实也不高,那么有什么方法可以进行改进呢?我们想,上面的递推式,我们取的是max(ri+rn−i)max(r_i +r_{n-i})max(ri​+rn−i​),即算当i确定时,就要进行两次递归,那么是不是可以减少递归的次数呢?
这里我们就进行改进:

  1. 从钢条的左边切割下长度为i的一段,只对右边剩下的一段继续进行切割,左边的不再切割
  2. 递推式简化为rn=max⁡1<j≤m(pi+rn−i)r_n=\max\limits_{1<j\leq m}(p_i+r_{n-i})rn​=1<j≤mmax​(pi​+rn−i​)
  3. 不做切割的方案就可以描述为:左边一段长度为n,收益为pnp_npn​,剩余一段长度为0,收益为r0r_0r0​=0。

这样对于每一个i,我们就减少了递归的次数,增加了效率!

5. 代码改进

# 简化后的算法
def cut_rod_recurision_2(p, n):if n == 0:return 0else:res = 0for i in range(1, n+1):res = max(res, p[i] + cut_rod_recurision_2(p, n-i))  # 递归一次,所以快return res

6. 思路再改进

其实我们思路改进后,还是用到了递归,只不过是减少了递归的使用次数而已,所以当n过大时,算法还是无法承受,效率不高。我们之前的两种方法,改进前以及改进后,都用到了递归,递推式分别为:
rn=max(pn,r1+rn−1,r2+rn−2,...,rn−1十r1)r_n=max(p_n,r_1 +r_{n-1},r_2+r_{n-2},...,r_{n-1}十r_1)rn​=max(pn​,r1​+rn−1​,r2​+rn−2​,...,rn−1​十r1​)
rn=max⁡1<j≤m(pi+rn−i)r_n=\max\limits_{1<j\leq m}(p_i+r_{n-i})rn​=1<j≤mmax​(pi​+rn−i​)
可以发现,这两种方法都是自上而下的切割方法。什么叫做自上而下的切割方法呢?就是把长度为n的进行切割为两段,再分别计算两段的最优价值,就这样,一步一步切割,一步一步计算,最后到不能切割为止,得到结果!时间复杂度为O(2n)O(2^n)O(2n)!
那这里,我们就提出了 动态规划(DP)的思路 :
自底向上的方法: 从短到长,把长度从0~n的钢条最优价格求出来,因为每次求出长度后都用列表储存,所以计算后面的长度时,直接从列表里取出相应切割方案对应的价值,相加即可,不需要递归,大大增加了效率!

7. 代码再改进

def cut_rod_dp(p, n):r = [0]for i in range(1, n+1):  # 下标i对应的数字就是长度为n=i的钢条的最优价格,所以i从1开始,把长度从1~n的钢条最优价格求出来res = 0for j in range(1, i+1):  # 求当n确定时,利用递推式求出此时的最优价格res = max(res, p[j] + r[i - j])r.append(res)return r[n]

思路很简单,代码也很简单!
当然,有了最大价值,我们还需要知道切割方案:

'''
TOPIC: 钢条切割: 自顶向下实现
author: Blue
time: 2020-08-19
QQ: 2458682080
'''# 重构解
def cut_rod_extend(p, n):r = [0]s = [0]for i in range(1, n+1):  # 下标i对应的数字就是长度为n=i的钢条的最优价格,所以i从1开始res_r = 0  # 记录价格的最大值res_s = 0  # 记录价格最大值对应方案的左边不切割部分的长度for j in range(1, i+1):if p[j] + r[i - j] > res_r:res_r = p[j] + r[i - j]res_s = jr.append(res_r)s.append(res_s)return r[n], s# 获取切割方案
def cut_rod_solution(p, n):r, s = cut_rod_extend(p, n)ans = []while n > 0:ans.append(s[n])n -= s[n]return ans

所有代码为:

# 自底向上的方法
def cut_rod_dp(p, n):r = [0]for i in range(1, n+1):  # 下标i对应的数字就是长度为n=i的钢条的最优价格,所以i从1开始,把长度从1~n的钢条最优价格求出来res = 0for j in range(1, i+1):  # 求当n确定时,利用递推式求出此时的最优价格res = max(res, p[j] + r[i - j])r.append(res)return r[n]# print(c2(p, 20))
# print(cut_rod_dp(p, 20))# 重构解
def cut_rod_extend(p, n):r = [0]s = [0]for i in range(1, n+1):  # 下标i对应的数字就是长度为n=i的钢条的最优价格,所以i从1开始res_r = 0  # 记录价格的最大值res_s = 0  # 记录价格最大值对应方案的左边不切割部分的长度for j in range(1, i+1):if p[j] + r[i - j] > res_r:res_r = p[j] + r[i - j]res_s = jr.append(res_r)s.append(res_s)return r[n], s# 获取切割方案
def cut_rod_solution(p, n):r, s = cut_rod_extend(p, n)ans = []while n > 0:ans.append(s[n])n -= s[n]return ansr, s = cut_rod_extend(p, 20)
print(s)
print(cut_rod_dp(p, 20))

结果为:

[0, 1, 2, 3, 2, 2, 6, 1, 2, 3, 10]  # 切割方案
30  # 最大价值

钢条切割问题——自底向上递归实现
时间复杂度O(n^2)

8. 总结

钢条切割问题——动态规划解法
递归算法由于重复求解相同子问题,效率极低
动态规划的思想:

  1. 每个子问题只求解一次,保存求解结果
  2. 之后需要此问题时,只需查找保存的结果

动态规划问题关键特征
什么问题可以使用动态规划方法?

  1. 最优问题
  2. 最优子结构
    • 原问题的最优解中涉及多少个子问题
    • 在确定最优解使用哪些子问题时,需要考虑多少种选择
  3. 重叠子问题

数据结构(python) —— 【34: 动态规划之钢条切割问题】相关推荐

  1. Python数据结构与算法-动态规划(钢条切割问题)

    一.动态规划(DP)介绍 1.从斐波那契数列看动态规划 (1)问题 斐波那契数列递推式: 练习:使用递归和非递归的方法来求解斐波那契数列的第n项 (2)递归方法的代码实现 import time # ...

  2. 算法导论15.1动态规划之钢条切割

    动态规划与钢条切割 1.分治算法与动态规划 相同点: 都是通过组合子问题的解来求解原问题 不同: 1.分治将问题划分为互不相交的子问题,递归地求解子问题,在将它们的解组合起来,求出原问题. 2.动态规 ...

  3. 算法导论-动态规划(钢条切割问题)

    写下文章来记录下自己学习算法导论的笔记 文章目录 写下文章来记录下自己学习算法导论的笔记 动态规划的目的 设计动态规划算法 钢条切割问题 问题描述 刻画问题结构(建立方程) 递归方程建立 带备忘录的自 ...

  4. 动态规划算法---钢条切割

    算法进阶---动态规划算法 钢条切割问题: 程序实现: 钢条切割问题: 程序实现: 方法一和方法二是对程序实现的不断深入,逐渐降低算法实现的时间复杂度. p = [0, 1, 5, 8, 9, 10, ...

  5. 《算法导论》中动态规划求解钢条切割问题

    动态规划算法概述 动态规划(dynamic programming)1是一种与分治方法很像的方法,都是通过组合子问题的解来求解原问题.不同之处在于,动态规划用于子问题重叠的情况,比如我们学过的斐波那契 ...

  6. 《算法导论》学习(十七)----动态规划之钢条切割(C语言)

    文章目录 前言 一.钢条切割问题 1.问题背景 2.问题描述 3.问题的难点 (1)情况较多 (2)消除重复子问题 二.问题解决方案 1.问题的特点 (1)最优化子结构 (2)重复子问题 2.最优化解 ...

  7. 动态规划:钢条切割问题

    一.题目 钢条切割问题 是<算法导论>一书中介绍动态规划时的一道引题.即: 某公司购买长钢条,将其切割为短钢条出售.假设切割工序没有成本支出,已知长度为 i 的钢条出售价格为 pi ,钢条 ...

  8. 【动态规划】钢条切割问题

    本人在学习<算法导论>的过程中,对于动态规划这部分的内容不是特别理解,于是决定做一下学习与解决记录,欢迎讨论交流. 文章目录 0- 动态规划问题的一般步骤 1- 问题描述 2-问题分析 3 ...

  9. 贪心、动态规划:钢条切割

    题目描述 Serling公司购买长钢条,将其切割为短钢条出售.切割工序本身没有成本支出.公司管理层希望知道最佳的切割方案. 假定我们知道Serling公司出售一段长为i英寸的钢条的价格为pi(i=1, ...

最新文章

  1. 关于HA-MIR镜像双机虚拟IP与周立功CANET-200T采用UDP模式通讯技巧
  2. Python自动化开发学习13-堡垒机开发
  3. 数据结构--图(Graph)详解(二)
  4. HarmonyOS应用开发——使用HUAWEI DevEco Studio创建第一个程序 HELLO WORLD!
  5. Linux 输入输出重定向 2>/dev/null和>/dev/null 2>1和2>1>/dev/nul
  6. 请给出计算231-1的python表达式_【填空题】计算2 32 -1的Python表达式可以书写为____...
  7. PHP爱讯云商城源码v0.7.0-新增app功能
  8. 监控长时间运行的查询(监控数据库性能的SQL )
  9. dp(0,1背包)-----高数Umaru系列(9)——哈士奇
  10. 深山红叶PE工具箱嫦娥一号纪念版
  11. C#的变迁史 - C# 5.0 之其他增强篇
  12. Friends 第一季英文学习整理
  13. 基于车载以太网的音视频传输 AVB vs RTP
  14. matlab矩阵求和速度慢,matlab – 将完整矩阵转换为完整矩阵的速度很慢?
  15. Kubernetes的Startup, Liveness, Readiness深入探索
  16. oracle的权限授予,oracle权限命令
  17. matlab 关于interpreter的使用
  18. QT总结10-绘制箭头
  19. 【Captain America Sentinel of Liberty HD】美国队长:自由哨兵 v1.0.2
  20. MySQL中xtrabackup备份恢复全攻略(r12笔记第11天)

热门文章

  1. java mcv_spring框架mcv的工作原理是什么?
  2. [USACO18DEC]Fine Dining
  3. SpringBoot使用爬虫(初级阶段)
  4. 由sizeof 这个“管”,窥一窥C语言这只“豹”
  5. java计算机毕业设计ssm兴发农家乐服务管理系统n159q(附源码、数据库)
  6. 大学计算机课考试难吗,大学阶段容易“挂科”的4门学科,考试难度较大,补考通过率还低...
  7. Sci-Hub十周年迎来解封!科研er的福音!附可用网址!
  8. Unity动画系统知识体系概览
  9. 内网穿透工具(永久免费、永不限速、开源)、一键启动、页面操作(支持window,mac),自定义二级域名
  10. 【20210326期AI简报】用RISC-V微控制器开发难不难?行人搜索AI框架新突破~