學習動態規劃問題時,較為經典的分析例題,分別通過遞迴,備忘錄和自下而上的方式基於python實現的練習。
首先由斐波那契數列進行練習:
# 斐波那契數列 遞迴
def fibo(n):
if n <= 0:
return 0
if n == 1:
return 1
return fibo(n-1)+fibo(n-2)
# 斐波那契數列 非遞迴
(一)自頂向下的備忘錄版本
def fibonacci(n):
sum_list = [0] * (n + 1)
def fibo(n, sum_list):
if sum_list[n] != 0:
return sum_list[n]
if n <= 2:
sum_list[n] = 1
else:
sum_list[n] = fibo(n-1, sum_list)+fibo(n-2, sum_list)
# print(sum_list)
return sum_list[n]
return fibo(n, sum_list)
通過定義sum_list列表(n+1個元素)來記錄斐波那契數列中每乙個值,
如果存在sum_list中的值,省去遞迴直接進行計算,
如果sum_list中沒有斐波那契中的值,
再利用遞迴進行計算並儲存在sum_list中。省去了重複計算。
(二)自低而上
def fibo(n):
if n <= 1:
return n
s1 = 0
s2 = 1
sum = 1
for i in range(1,n):
sum = s1+ s2
s1 = s2
s2 = sum
return sum
但是備忘錄方法還是使用到了遞迴,並產生額外的開銷。
所以,可以先運算元問題,fib(1),fib(2),fib(3)……等,
即動態規劃核心:先計算子問題再計算父問題。
現在轉至切割鋼條問題:
例題:鋼條切割
(一)
# 遞迴版本
def value_max(p, n):
if n == 0:
return 0
q = 0
for i in range(0, n):
q = max(q, p[i]+value_max(p, n-i-1))
return q
(二)
同斐波那契,多新增了乙個max的函式用來篩選,再新增乙個列表r用來記錄。
# 備忘錄版本
def cutmemo(p, n):
r = [0]* (n+1)
def value_max(p, n, r):
if n == 0:
return 0
q = 0
for i in range(0, n):
q = max(q, p[i] + value_max(p, n-i-1, r))
r[i] = q
print(r)
return q
return value_max(p, n, r)
(三)
# 自下而上的動態規劃
def cutmemo(p, n):
r = [0] * (n+1)
for i in range(1, n+1):
if n == 0:
return 0
q = 0
for j in range(1, i+1):
q = max(q, p[j-1]+r[i-j])
r[i] = q
return r
文章參考 動態規劃 鋼條切割
一家公司購買長鋼條,將其切割成短鋼條 切割本身沒有成本,長度為i的短鋼條的 為pi。那給定一段長度為n的鋼條和乙個 表pi,求鋼條的切割方案使得收益rn最大。如乙個pi如下 長度i12 3456 78910 pi15 891017 1720 2430 在距離鋼條左端i長度處,我們總是可以選擇切割或者...
動態規劃 鋼條切割
這是演算法導論動態規劃的乙個例子,自己實現了一下 給定乙個長度為n英吋的鋼條和乙個 表pi i 1,2 n 求切割鋼條方案,使得銷售收益rn最大。注意,如果長度為n的鋼條 pn足夠大,則最優解可能就不需要切割。分析 如下 include include include using namespace...
動態規劃 鋼條切割
動態規劃 dynamic programming 什麼是動態規劃,我們要如何描述它?動態規劃演算法通常基於乙個遞推公式及乙個或多個初始狀態。當前子問題的解將由上一次子問題的解推出。動態規劃和分治法相似,都是通過組合子問題的解來求解原問題。分治法將問題劃分成互不相交的子問題,遞迴求解子問題,再將他們的...