算法导论程序35--动态规划(钢条切割)
来源:互联网 发布:健身房健身计划软件 编辑:程序博客网 时间:2024/05/29 05:52
求解一个如何切割钢条的问题:
公司购买长钢条,将其切割为短钢条出售。切割工序本身没有成本支出,公司管理层希望知道最佳的切割方案。
假设我们知道公司出售一段长度为i英寸的钢条的价格为pi(i=1,2,...,)
钢条切割问题:
给定一段长度为n英寸的钢条和一个价格表pi(i=1,2,...,n),求切割钢条方案,是的销售收益rn最大。
注意:如果长度为n英寸的钢条的价格的pn足够大,最优解可能就是完全不需要切割。
长度为n英寸的钢条共有2的n-1次方种不同的切割方案,因为在距离钢条i(i=1,2,...,n-1)英寸处,我们总是可以选择切割或不切割。
如果一个最优解将钢条切割为k段(对某个1=<k<=n),那么最优切割方案:
n=i1+i2+i3+...+ik
将钢条切割为长度分别为i1,i2,...,ik的小段,得到最大收益:
rn=pi1+pi2+...+pik
更一般地,对于rn(n>=1),我们可以用更短的钢条的最优切割收益来描述它:
第一个参数pn表示不切割,直接出售长度为n英寸的钢条的方案。其他n-1个参数对应另外n-1种方案:
对每个i=1,2,...,n-1,首先将钢条切割为长度为i和n-i的两段,接着求解这两段的最优切割收益
由于无法预知哪种方案会获得最优收益,我们必须考察所有可能的i,选取其中收益最大者。
为了求解规模为n的原问题,我们先求解形式完全一样,但规模更小的子问题。即当完成首次切割后,我们将两段钢条看成两个独立的钢条切割问题实例。我们通过组合两个相关子问题的最优解。并在所有可能的两段切割方案中选取组合收益最大者,构成原问题的最优解。
最优子结构性质:
问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。
自顶向下递归实现:
def cut_rod(p,n): if n==0: return 0 q=float("-inf") for i in range(0,n): q=max(q,p[i]+cut_rod(p,n-i-1)) return qif __name__=='__main__': p=[1,5,8,9,10,17,17,20,24,30] for i in range(1,11): print("长度为",i,"的钢条的切割最大收益为:",end='') print(cut_rod(p,i))运行:
>>> ==== RESTART: D:\Program Files\Python\test\algorithms\算法导论\35-cut-rod.py ====长度为 1 的钢条的切割最大收益为:1长度为 2 的钢条的切割最大收益为:5长度为 3 的钢条的切割最大收益为:8长度为 4 的钢条的切割最大收益为:10长度为 5 的钢条的切割最大收益为:13长度为 6 的钢条的切割最大收益为:17长度为 7 的钢条的切割最大收益为:18长度为 8 的钢条的切割最大收益为:22长度为 9 的钢条的切割最大收益为:25长度为 10 的钢条的切割最大收益为:30
但是,上面的程序真的效率好低呀!
使用动态规划方法求解最优钢条切割问题:
朴素递归算法之所以效率很低,是因为它反复求解相同的子问题。因此,动态规划方法仔细安排求解顺序,对每个子问题之求解一次,并将结果保存下来。如果随后再次需要此子问题的解,只需查找保存的结果,而不必重新计算。
因此,动态规划方法是付出额外的内存空间来节省计算时间,是典型的时空权衡的例子。
两种实现方式:
(1)带备忘的自顶向下方法:
def memorized_cut_rod(p,n): r=[] for i in range(n): r.append(float("-inf")) return memorized_cut_rod_aux(p,n,r)def memorized_cut_rod_aux(p,n,r): if r[n-1]>=0: return r[n-1] if n==0: q=0 else: q=float("-inf") for i in range(0,n): q=max(q,p[i]+memorized_cut_rod_aux(p,n-i-1,r)) r[n-1]=q return q
运行:
print("动态规划方法:") for i in range(1,11): print("长度为",i,"的钢条的切割最大收益为:",end='') print(memorized_cut_rod(p,i))
动态规划方法:长度为 1 的钢条的切割最大收益为:1长度为 2 的钢条的切割最大收益为:5长度为 3 的钢条的切割最大收益为:8长度为 4 的钢条的切割最大收益为:10长度为 5 的钢条的切割最大收益为:13长度为 6 的钢条的切割最大收益为:17长度为 7 的钢条的切割最大收益为:18长度为 8 的钢条的切割最大收益为:22长度为 9 的钢条的切割最大收益为:25长度为 10 的钢条的切割最大收益为:30
(2)自底向上:
def bottom_up_cut_rod(p,n): r=[] for i in range(n+1): r.append(float("-inf")) r[0]=0 for j in range(n): q=float("-inf") for i in range(j+1): q=max(q,p[i]+r[j-i]) r[j+1]=q return r[n]运行:
print("动态规划方法2:") for i in range(1,11): print("长度为",i,"的钢条的切割最大收益为:",end='') print(bottom_up_cut_rod(p,i))
动态规划方法2:长度为 1 的钢条的切割最大收益为:1长度为 2 的钢条的切割最大收益为:5长度为 3 的钢条的切割最大收益为:8长度为 4 的钢条的切割最大收益为:10长度为 5 的钢条的切割最大收益为:13长度为 6 的钢条的切割最大收益为:17长度为 7 的钢条的切割最大收益为:18长度为 8 的钢条的切割最大收益为:22长度为 9 的钢条的切割最大收益为:25长度为 10 的钢条的切割最大收益为:30
重构方法:
长度为j的钢条不仅计算最大收益rj,还保存最优解对应的第一段钢条的切割长度sj。
def extended_bottom_up_cut_rod(p,n): r=[] s=[] for i in range(n+1): r.append(float("-inf")) s.append(float("-inf")) r[0]=0 s[0]=0 #j+1表示钢条的长度,i+1表示第一段的长度 for j in range(n): q=float("-inf") for i in range(j+1): if q<p[i]+r[j-i]: q=p[i]+r[j-i] s[j+1]=i+1 r[j+1]=q return r,s
运行结果:
print("动态规划重构方法:") for i in range(1,11): print("长度为",i,"的钢条的切割最大收益为:",extended_bottom_up_cut_rod(p,i)[0][i],' ',end='') print("第一段钢条的切割长度为:",extended_bottom_up_cut_rod(p,i)[1][i])
动态规划重构方法:长度为 1 的钢条的切割最大收益为: 1 第一段钢条的切割长度为: 1长度为 2 的钢条的切割最大收益为: 5 第一段钢条的切割长度为: 2长度为 3 的钢条的切割最大收益为: 8 第一段钢条的切割长度为: 3长度为 4 的钢条的切割最大收益为: 10 第一段钢条的切割长度为: 2长度为 5 的钢条的切割最大收益为: 13 第一段钢条的切割长度为: 2长度为 6 的钢条的切割最大收益为: 17 第一段钢条的切割长度为: 6长度为 7 的钢条的切割最大收益为: 18 第一段钢条的切割长度为: 1长度为 8 的钢条的切割最大收益为: 22 第一段钢条的切割长度为: 2长度为 9 的钢条的切割最大收益为: 25 第一段钢条的切割长度为: 3长度为 10 的钢条的切割最大收益为: 30 第一段钢条的切割长度为: 10
下面的过程,接受两个参数:价格表p和钢条长度n,然后调用extended_bottom_up_cut_rod(p,n)来静思园切割下来的每段钢条的长度s[1...n]。最后输出长度为n的钢条的完整的最优切割方案:
def print_cut_rod_solution(p,n): (r,s)=extended_bottom_up_cut_rod(p,n) while n>0: print(s[n],' ',end='') n=n-s[n] print()运行结果:
for i in range(1,11): print("长度为",i,"的钢条的切割最大收益的切割方案为:",end='') print_cut_rod_solution(p,i)
长度为 1 的钢条的切割最大收益的切割方案为:1 长度为 2 的钢条的切割最大收益的切割方案为:2 长度为 3 的钢条的切割最大收益的切割方案为:3 长度为 4 的钢条的切割最大收益的切割方案为:2 2 长度为 5 的钢条的切割最大收益的切割方案为:2 3 长度为 6 的钢条的切割最大收益的切割方案为:6 长度为 7 的钢条的切割最大收益的切割方案为:1 6 长度为 8 的钢条的切割最大收益的切割方案为:2 6 长度为 9 的钢条的切割最大收益的切割方案为:3 6 长度为 10 的钢条的切割最大收益的切割方案为:10
- 算法导论程序35--动态规划(钢条切割)
- 算法导论--动态规划(钢条切割)
- 算法导论 - 动态规划 - 钢条切割
- 算法导论---------动态规划之钢条切割
- 动态规划-钢条切割《算法导论》
- 算法导论 动态规划之钢条切割
- 算法导论之动态规划:钢条切割
- 钢条切割--动态规划--算法导论
- 算法导论-动态规划-钢条切割
- 《算法导论》动态规划钢条切割问题
- 动态规划之钢条切割(算法导论)
- 算法导论--第15章 动态规划--钢条切割
- 算法导论15章 动态规划 之 钢条切割
- 算法导论系列文章之动态规划-钢条切割
- 算法导论 第15章 动态规划之钢条切割
- 算法导论—动态规划之钢条切割
- 算法导论:第15章 动态规划_1钢条切割
- 算法导论 第15章 动态规划:15.1钢条切割
- 数据结构之总述
- 索尼新型CMOS图像传感器内置偏振元件
- find命令进阶(二):对找到的文件执行操作exec
- LC 2 pointer summary
- 数学中的特殊字符
- 算法导论程序35--动态规划(钢条切割)
- 编译的过程
- H
- 为什么Android Studio通过app打电话发短信时程序会崩溃
- effective Java读书笔记-通用程序设计
- postgresql-9.X 的 slave 端的 recovery.conf 文件
- u3d 切割texture贴图的方法
- session超时设置
- CodeChef