Day2补充:钢管切割问题

转自:https://blog.csdn.net/cyp331203/article/details/42806159

Day2补充:钢管切割问题

一. 问题背景:

某公司生产长钢管,然后一般,会将钢条切断,变成不同长度,然后去售卖。其中有个问题是,不同长度的钢管的售价是不一样的,但是它们并不是完全按照比例来,比如2米的钢管售价要比3米的钢管售价要少,但是并不是2比3的比例。钢管的长度售价表如下:

长度i 1 2 3 4 5 6 7 8 9 10
价格P_{i} 1 5 8 9 10 17 17 20 24 30

于是问题就来了,比如30米长的钢管,要如何切割,切割成多长的几条,才能让售价最高,收益最高呢?

二. 解决思路:

1.朴素算法:

最简单直接的想法,就是用暴力破解,n长的钢管,可以分解成i长和n-i长的两段,因为i可以从0~n取值,所以我们可以对i不进行继续切割,于是对于长为i的这一段,可以直接调用价钱数组p[i]来得到价钱,然后加上对n-i递归调用求最优收益的函数的返回值。在过程之中记录这些组合的最优收益,等循环结束的时候,就能得到最优的收益价钱。

假设r[n]代表的是n长的钢管的切割最佳收益值,数组p代表上面表中的价格,其中p[0]=0,从p[1]~p[10]对应上面表中的数据,那么按照上面的想法,有公式:

                                                 r[n]=max(p[i]+r[n-1]),1\leq i\leq n,当n=0时,r[n]=0,因为0长的钢管售价当然为0。

这种方法比较容易理解,但是性能是不是好呢?

可以简单的以n=4的情况来看一下:

        n=4的划分(其中前面的那一段是直接使用p[i],后面一段调用函数来求最佳收益):

扫描二维码关注公众号,回复: 11500390 查看本文章

            cut_rod(p,4)的划分可能:

                ①1长和3长:p[1]+cut_rod(p,3)

                ②2长和2长:p[2]+cut_rod(p,2)

                ③3长和1长:p[3]+cut_rod(p,1)

                ④4长和0长:p[4]+cut_rod(p,0)

        而其中cut_rod(p,3)又可以划分为数组p中元素与cut_rod(p,0),cut_rod(p,1)和cut_rod(p,2);以此类推,可以给出一种以递归调用树的形式展示cut_rod递归调用了多少次:

          

不难从图中看出,做了大量重复工作,以n=2的节点为例,分别在n=4和n=3的时候都被调用了。根据上图,可以给出递归调用次数的一个公式,假设T(n)表示cut_rod第二个参数为n时的调用次数,T(0)这时候是为1的,因为根结点的第一次调用也要算进去。于是有:

                                                             T(n)=1+T(0)+T(1)+...+T(n-1)

使用归纳法,可以比较容易的得出:T(n)=2^n。

指数次幂的调用次数,显然太大,我们稍微让n大一点,则会让整个过程变的漫长。

2. 动态规划算法

而实际上我们不需要在每次都去重新计算cut_rod的在n=2时的结果,只需要在第一次计算的时候将结果保存起来,然后再需要的时候直接使用即可。这其实就是所谓的动态规划算法。

这里的思路有两种,一种叫带备忘的自顶向下方法,是顺着之前的代码,当需要的时候去检查是不是已经计算好了,如果是,则直接使用,如果不是,则计算,并保存结果。第二种思路是自底向上方法,不论需不需要,先将子问题一一解决,然后再来解决更高一级的问题,但要注意的是,我们需要先从最小的子问题开始,依次增加规模,这样每一次解决问题的时候,它的子问题都已经计算好了,直接使用即可。

 

猜你喜欢

转载自blog.csdn.net/A994850014/article/details/94001189
今日推荐