问题描述
问题的最优解包含相关子问题的最优解,这些子问题我们可以独立求解。
应用以下公式:
方法1:暴力法
长度为n的钢条可以有2^(n-1)中切割方案,因为离钢条左端距离分别为1,2,……,(n-1)的位置都有切或不切(0或1)两种选择,
但是我认为有好多重复的情况,假设切割的位置存储在数组中,那么[1]和[n-1]其实是一样的,因为都代表切成长为1和(n-1)的两段。但是具体重复情况(类似回文数的数量)有多少我一下子不知道怎么计算,但是数量级还是指数级的!!!
以下的图中伪代码基本相当于python代码,重大区别就是数组下标 i 有些差别!!!在我写的代码中
length = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
profit = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
def cut_rod(p, n):
if n == 0:
return 0
q = -1
for i in range(n):
q = max(q, p[i]+cut_rod(p, n-i))
return q
print(cut_rod(profit, 9))
运行结果:
C:\Users\liuxiang15\Desktop\homework3>python rod_cutting.py
Traceback (most recent call last):
File "rod_cutting.py", line 11, in <module>
print(cut_rod(profit, 9))
File "rod_cutting.py", line 9, in cut_rod
q = max(q, p[i]+cut_rod(p, n-i))
File "rod_cutting.py", line 9, in cut_rod
q = max(q, p[i]+cut_rod(p, n-i))
File "rod_cutting.py", line 9, in cut_rod
q = max(q, p[i]+cut_rod(p, n-i))
[Previous line repeated 993 more times]
File "rod_cutting.py", line 8, in cut_rod
for i in range(n):
RecursionError: maximum recursion depth exceeded in comparison
方法2:带备忘的自顶向下法
为了避免“自顶向下递归算法”中出现的重复计算重叠子问题的情况,用数组r存储不同长度下的最大效益
代码:
length = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
profit = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
def memorized_cut_rod(p, n):
r = [-1]*(n+1)
return memorized_cut_rod_aux(p, n, r)
def memorized_cut_rod_aux(p, n, r):
if r[n] > 0:
return r[n]
q = -1
if n == 0:
q = 0
else:
for i in range(1, n+1):
q = max(q, p[i-1]+memorized_cut_rod_aux(p, n-i, r))
r[n] = q
return q
for i in range(1, 11):
print(memorized_cut_rod(profit, i))
运行结果:
C:\Users\liuxiang15\Desktop\homework3>python rod_cutting.py
1
5
8
10
13
17
18
22
25
30
方法3:自底向上法
length = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
profit = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
def bottom_up_cut_rod(p, n):
r = [0]*(n+1)
for j in range(1, n+1):
q = -1
for i in range(1,j+1):
q = max(q, p[i-1]+r[j-i])
r[j] = q
return r[n]
for i in range(1, 11):
print(bottom_up_cut_rod(profit, i))
C:\Users\liuxiang15\Desktop\homework3>python rod_cutting.py
1
5
8
10
13
17
18
22
25
30
方法4:扩展的自底向上法(s数组存储切割位置)
代码增加了一个功能,待切割长度n可以大于len(profit)
length = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
profit = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
def extended_bottom_up_cut_rod(p, n):
r = [0]*(n+1)
s = [0]*(n+1)
for j in range(1, n+1):
q = -1
for i in range(1,j+1):
if i <= len(profit):
if q < p[i-1]+r[j-i]:
q = p[i-1]+r[j-i]
s[j] = i
else:
if q < r[i]+r[j-i]:
q = r[i] + r[j-i]
s[j] = i
r[j] = q
# return r[n],s[n]
return r,s
print(extended_bottom_up_cut_rod(profit, 15))
C:\Users\liuxiang15\Desktop\homework3>python rod_cutting.py
([0, 1, 5, 8, 10, 13, 17, 18, 22, 25, 30, 31, 35, 38, 40, 43], [0, 1, 2, 3, 2, 2, 6, 1, 2, 3, 10, 1, 2, 3, 2, 2])
方法4.1:使用方法4函数来存储切割段长在数组中
# method of how to cut the rod
def cut_rod_solution(p, n):
(r,s) = extended_bottom_up_cut_rod(p, n)
print(r)
print(s)
cut_method = []
while n > 0:
cut_method.append(s[n])
# print(s[n])
n -= s[n]
return cut_method
print(cut_rod_solution(profit, 15))
C:\Users\liuxiang15\Desktop\homework3>python rod_cutting.py
[0, 1, 5, 8, 10, 13, 17, 18, 22, 25, 30, 31, 35, 38, 40, 43]
[0, 1, 2, 3, 2, 2, 6, 1, 2, 3, 10, 1, 2, 3, 2, 2]
[2, 3, 10]
不足:
没有对复杂度的计算分析,稍后补充!
参考博客
https://blog.csdn.net/yangfengyougu/article/details/82843134
https://blog.csdn.net/u010183397/article/details/46933639
https://www.cnblogs.com/tgycoder/p/4980655.html
https://segmentfault.com/a/1190000015150097?utm_source=tag-newest
欢迎大家批评指正!!!