UTF8gbsn
Introduction
先来看看问题,加入我们有一个价格表
length(i) 1 2 3 4 5 6 7 8 9 10
price( ) 1 5 8 9 10 17 17 20 24 30
那么,我们现在有一根刚才长度为
,你是一个加工商,需要把长度为
的刚才切割为
长度卖出去。问怎么才能卖出最高的价格。
Recursive
alg
我们先来看看一个递归解法。也就是把问题分治,
当一个刚才被切割为2部分的时候。我们可以分别计算这两部分的最大收益,然后得出这种分法的最大收益。递归而来,最终可以得到最终的收益。
CUT-ROD(p, n)
if n == 0
return 0
q = - infinity
for i = 1 to n
q = max(q, p[i]+CUT-ROD(p, n-i))
return q
complexity
因为是一个递归算法我们用调用的次数来衡量算法的复杂度。那么首先,我们先来看看
这个可以用归纳法求出来,也就是说
所以,调用是指数级别的的增长。比如当 时,程序就需要运行数分钟之久。所以,递归解法不是一个可取的算法。
dynamic programming
我们仔细来分析一下,问题。对于上面提到的递归算法,实际上重复计算了很多东西。比如,当 的时候。
-
第一次循环中
-
把 展开
可以看到,第一步中第二项和第二步中的第一项的
CUT-ROD是一模一样的。但是因为是递归。实际上我们对这个函数计算了两次。而动态规划的核心就是如何把已经计算的东西缓存起来,让计算更高效。
top-down
自顶向下的方法。
CUT-ROD(p, n)
let r[0..n] be a new array
for i = 0 to n
r[i] = - Infinity
return CUT-ROD-AUX(p, n, r)
这里引入了一个辅助函数
CUT-ROD-AUX(p, n, r)
if r[n] > = 0
return r[n]
if n == 0
q = 0
else q = - Infinity
for i = 1 to n
q = max(q, p[i] + CUT-ROD-AUX(p, n-i, r))
r[n] = q
return q
bottom-up
更为简单 CUT-ROD(p, n)
let r[0..n] be a new array
r[0] = 0
for j = 1 to n
q = - Infinity
for i = 1 to j
q = max(q, p[i]+r[j-1])
r[j] = q
return r[n]
complexity
由于我们使用了两层循环所以复杂度为
Reconstruct a solution
EX-CUT-ROD(p, n)
let r[0..n] and s[0..n] be new arrays
r[0] = 0
for j = 1 to n
q = - Infinity
for i = 1 to j
if q<p[i]+r[j-i]
q = p[i]+r[j-i]
s[j] = i
r[j] = q
return r and s
PRINT-CUT-ROD(p,n)
(r,s) = EX-CUT-ROD(p, n)
while n > 0
print s[n]
n = n - s[n]
The End
至此,动态规划解决钢管切割问题,就完成了。