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

本人在学习《算法导论》的过程中,对于动态规划这部分的内容不是特别理解,于是决定做一下学习与解决记录,欢迎讨论交流。

0- 动态规划问题的一般步骤

1- 刻画一个最优解的结构特征
2- 递归定义最优解的值
3- 计算最优解的值,通常采用自底向上的方法
4- 利用计算出的信息构造一个最优解

1- 问题描述

Serling 公司购买长钢条,将其切割为锻钢条出售。切割工序本身没有成本支出。公司管理层希望知道最佳的切割方案。
假定我们知道Serling公司出售一段长度为i英寸的钢条的价格为pi(i = 1, 2,…,单位为美元)。钢条的长度均为整英寸。下表给出了一个价格表的样例。

长度i 1 2 3 4 5 6 7 8 9 10
价格p(i) 1 5 8 9 10 17 17 20 24 30

2-问题分析

钢条切割问题是这样的:给定一段长度为n英寸的钢条和一个价格表p(i)(i = 1, 2,…,n),求切割钢条方案,使得销售收益rn最大。注意如果长度为n英寸的钢条价格p(n)足够大,最优解可能是完全不需要切割。

考虑n=4的情况。下图给出了4英寸钢条的所有可能切割方案,包括根本不切割的方案。从下图可以看出,将一段长度为4英寸的钢条切割为两段各长为2英寸的钢条,将产生p(2)+p(2)=5+5=10的收益,为最优解。

图1 钢条切割方案

对于最优收益rn(n≥1)可以用更短的钢条的最优收益来描述:

r n = max(p n,r 1+r n-1,r 2+r n-2,...,r n-1+r 1)

第一个参数pn对应不切割,直接出售长度为n英寸的钢条的方案。其中n-1个参数对应另外n-1种方案:对每个i = 1, 2, …, n-1,首先将钢条切割为i和n-i的两段,接着求解这两段的最优切割收益ri和rn -i(每种方案的最优收益为两段的最优收益之和)。由于无法预知那种方案的将获得最佳收益,所以必须考虑所有可能的i,选取其中的收益最大者。如果直接出售圆钢条会获得最大收益,当然可以不做任何切割。

可以看出,通过组合两个子问题(完成首次切割之后,即将问题转化为求解两个独立的钢条切割问题实例)的最优解,并在所有可能得两段切割方案中选取组合收益最大者,构成原问题的最优解。

钢条问题是满足最优子结构的(optimal substructure) 性质的:问题的最优解由相关子问题的最优解组合而成,而且这些子问题可以独立求解。

3-自顶向下递归实现

简单的递归求解方法: 将钢条从左边切割下长度为i的一段,只对右边剩余的长度为n-i的一段继续进行切割(递归求解),对左边的一段则不再进行切割。问题的分解方式为:将长度为n的钢条分解为左边的开始一段,以及剩余部分继续分解的结果。这样,不做任何切割的方案可以描述为:第一段的长度为你n,收益为pn,剩余部分的长度为0,对应的收益r0=0。 于是可以得到如下公式:

r n = max(p i +r n-i)

原问题的最优解只包含一个相关子问题(右边剩余部分)的解。下面给出朴素递归算法的解:

#include <iostream>
#include <vector>
#include <limits.h>
#include <algorithm>

using namespace std;

vector<int> price{
   1, 5, 8, 9, 10, 17, 17, 20, 24, 30};//钢条对应的价格

int CutRod(vector<int> &price, int length){
   
    if(length == 0) return 0;//如果钢条长度为0,直接返回
    int maxvalue = INT_MIN;//因为钢条价格为正值,所以首先默认maxvalue为最小值
    for(int i = 1; i <= length; ++i){
   
    //取前一次迭代算得的maxvalue与本次迭代结果的最大值
    //迭代:当前钢条段的价值 + 剩余右边钢条的价值
    //(这里因为下标从0开始,所以有-1)
        maxvalue = max(maxvalue, price[i - 1] + CutRod(price, length - i));
    
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值