動態規劃原理講解(下)
阿新 • • 發佈:2018-12-04
本章節主要結合動態規劃的例項程式碼進行講解,使用python語言。
題目一: 選出的數字不能相鄰,且使得選出的數字總和最大。
1.1 問題原理介紹
比如:可以選擇1和9,結果為10。
但是如果選擇4和9,結果為13,則結果為最優的。
並且選擇的時候不一定非要選擇兩個,也可以選擇其它方案,如下圖所示
但是選出的方法結果也不會超過13,所以該方案並非最優。
1.2 程式碼與例項講解
上節我們採用的是選與不選的解決方法來解決動態規劃問題,對於該例項同樣適用。
例項內容解析:OPT(6)為求解到下標為6的位置的最佳方案是什麼?
分析OPT(6):(+)代表選擇,(-)代表不選。
當然這裡面有很多的重疊子問題:OPT(3)、OPT(4)
遞迴方程表示上述過程:
程式程式碼:
In [6]: arr=[1,2,4,1,7,8,3] def rec_opt(arr,i): if i==0: return arr[0] elif i==1: return max(arr[0],arr[1]) else: A=rec_opt(arr,i-2)+arr[i] B=rec_opt(arr,i-1) return max(A,B) rec_opt(arr,6) Out[6]: 15
存在的問題:上述程式碼存在重疊子問題,運算速度會很慢,時間複雜度會達到,採用非遞迴方法:
import numpy as np arr=[1,2,4,1,7,8,3] #非遞迴方法 def dp_opt(arr): opt=np.zeros(len(arr)) opt[0]=arr[0] opt[1]=max(arr[0],arr[1]) for i in range(2,len(arr)): A=opt[i-2]+arr[i] B=opt[i-1] opt[i]=max(A,B) return opt[len(arr)-1] dp_opt(arr) output: 15.0
題目二:從一個數組中選出一堆數字,使得這些數字的和等於給定的數字9,查詢是否存在這樣的方案?如果存在這樣的方案,則列印True,否則False。
假設:所有的數字都是正整數
思路與上題一致。
subset(i,s)考慮第i個數字選不選,s為要求的數字。
只要左右兩邊的任何一個方案成立,那麼就時True。中間用or連線。
出口設計:
(1)在處理到一半的時候s已經變為0。比如當我進行到arr[2]時,後面的已經能夠得到我想要的數字,則前面的已經沒有必要進行計算。直接輸出True。
(2)如果i=0,arr[0]=s時才能返回True。
(3)如果arr[i]>s,就只考慮不選arr[i]這個數字的情況。
遞迴過程:
程式程式碼:
#三個出口條件,採用遞迴方法
aar=[3,34,4,12,5,2]
def rec_subset(arr,i,s):
if s==0:
return True
elif i==0:
return arr[0]==s
elif arr[i]>s:
return rec_subset(arr,i-1,s)
else:
A=rec_subset(arr,i-1,s-arr[i])
B=rec_subset(arr,i-1,s)
return A or B
print(rec_subset(arr,len(arr)-1,9))
print(rec_subset(arr,len(arr)-1,10))
print(rec_subset(arr,len(arr)-1,11))
print(rec_subset(arr,len(arr)-1,12))
output:
True
True
True
True
採用非遞迴的形式:
思路分析:
程式程式碼:
#採用非遞迴方法,使用二維陣列儲存中間過程
#三個出口條件,採用遞迴方法
import numpy as np
aar=[3,34,4,12,5,2]
def dp_subset(arr,S):
subset=np.zeros((len(arr),S+1),dtype=bool)
subset[:,0]=True
subset[0,:]=False
subset[0,arr[0]]=True
for i in range(1,len(arr)):
for s in range(1,S+1):
if arr[i]>s:
subset[i,s]=subset[i-1,s]
else:
A=subset[i-1,s-arr[i]]
B=subset[i-1,s]
subset[i,s]=A or B
r , c = subset.shape
return subset[r-1,c-1]
print(dp_subset(arr,9))
print(dp_subset(arr,10))
print(dp_subset(arr,11))
print(dp_subset(arr,12))
output:
True
True
True
False