动态规划算法 ——钢条切割问题

Posted 爱思考的coder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划算法 ——钢条切割问题相关的知识,希望对你有一定的参考价值。

动态规划算法

——钢条切割问题


 (原创内容,转载请注明来源,谢谢)


一、问题

长度为n米的钢条,需要切割成x断来贩卖。假设没有切割成本,且每种长度能够销售的价格是一个确定的值(例如长度1米可以卖1元,长度2米可以卖5元,长度3米可以卖6元等)。

现在假定已知每种长度可以销售的价格,求长度为n米的钢条切割后,可以销售得到的最大利润。

 

二、分析

对于任意长度为i米的钢条,要获得最大价值,要么不需要切割整个i来售卖,要么从左开始切割i米(这一段不再切割),使得i米的价格加上剩余i-i米切割后的价格的总和最大。

 

三、解法一

根据分析可知,可以遍历不同的长度,并且取得最终的最大值。

代码如下:

public function solvingSlowDynamic($prices, $length)

{

$pricesCount = count($prices);

//待售长度为0的钢条,或价格表只有长度为0的价格,

if(empty($length) || 1 >= $pricesCount)

{

return 0;

}

$salePrice = 0;

//从切割长度为1开始,逐个计算价格

for($i = 1;$i < $pricesCount-1; $i++)

{

$salePrice = max($salePrice, $prices[$i] + $this->solvingSlowDynamic($prices, $length-$i));

}

return $salePrice;

}

 

四、解法二

解法一有个问题,当钢条长度太长时,计算会很慢。因为会重复计算许多中间节点的长度最佳售价。例如长度为10的钢条,从左切可以是0-101-92-83-7...,要计算9的售价则又需要计算0-91-82-73-6...,可以看到长度为23等的钢条,其价格需要重复计算。

易知,长度为n的钢条,有2^n种切割方案,故需要计算2^n次长度的售价。

为了加快速度,可以把中间结果缓存。

代码如下:

private $lengthPrices = array();//用于缓存中间计算结果

public function solvingFastDynamic($prices, $length)

{

//如果已经有缓存的结果则直接返回

if(isset($this->lengthPrices[$length]))

{

return $this->lengthPrices[$length];

}

$pricesCount = count($prices);

if(empty($length) || 1 >= $pricesCount)

{

return 0;

}

$salePrice = 0;

for($i = 1;$i < $pricesCount-1; $i++)

{

$salePrice = max($salePrice, $prices[$i] + $this->solvingSlowDynamic($prices, $length-$i));

}

//缓存计算结果

$this->lengthPrices[$length] = $salePrice;

return $salePrice;

}

 

五、解法三

除了缓存中间结果,还可以采用自底向上的方式计算,即先计算长度为0123...的,则在计算长度为n的钢条时,可以直接利用前面的计算结果进行计算。

代码如下:

public function solvingNewDynamic($prices, $length)

{

//自底向上,计算出每个长度的最佳售价

$lengthPrices = array(0 => 0);

//记录每种长度下的最左端切割长度

$cutLength = array(0 => 0);

$pricesCount = count($prices);

for($i = 1;$i < $pricesCount-1; $i++)

{

$salePrice = 0;

for($j = 1; $j <= $i; $j++)

{

$tmpSum = $prices[$j] + $lengthPrices[$i-$j];

if($salePrice < $tmpSum)

{

$salePrice = $tmpSum;

//记录长度为i的钢条的最佳第一段切割长度

$cutLength[$i] = $j;

}

}

//记录长度为i的最佳售价

$lengthPrices[$i] = $salePrice;

}

return array($lengthPrices, $cutLength);

}

上面的解法中,除了计算出每个长度的最佳售价,还计算出每个长度的最左端的切割方案。实际中,如果需要长度为n的切割方案,则根据数组可以查出第一段的切割长度,假设为i,则此时再查表,找到长度为i的钢条的第一段切割方案。以此类推,推算出最终的切割方案。


——written by linhxx 2018.05.13

以上是关于动态规划算法 ——钢条切割问题的主要内容,如果未能解决你的问题,请参考以下文章

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

动态规划 - 钢条切割

动态规划入门一:钢条切割问题

习题—动态规划贪心算法

动态规划学习笔记--对于钢条切割方案的思考

动态规划钢条切割问题