動態規劃演算法和分治法類似,都是將帶求解問題分解為若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的答案。與分治法不同的是,動態規劃要用乙個表來記錄所有已解決的子問題的答案。不管該問題是否以後會被用到,只要它被計算過,就將其結果填入表中。在需要時從表中找出答案,避免大量重複計算,從而得到多項式時間演算法。通常按一下幾個步驟設計動態規劃演算法:
(1)找出最優解性質,刻畫最優解結構;
(2)遞迴的定義最優值;
(3)以自底向上的方式計算最優值;
(4)根據計算最優值得到的資訊,構造最優解。
具體例項有:矩陣連乘,最長公共子串行,流水排程作業,0-1揹包問題,最優二叉搜尋樹等。
問題描述:給定兩個序列 x = 和y = ,找出x和y的最長公共子串行。
最優解:最長公共子串行的長度 m[ i ][ j ]以及相應的位置b[ i ][ j ]。
遞迴定義最優值:
第一種情況:當 i = 0,或者 j = 0 時,長度為 0;
第二種情況:當 xi = yi 時,表示長度等於子串行(去掉 i 位置元素後的序列)+1, 1 表示xi(或者 yi );b[ i ][ j ] = 1
第三種情況:當 xi != yi 時,表示兩個不同子串行公共長度的最大值。 b[ i ][ j ]=2,b[ i ][ j ]=3
時間複雜度:需要計算每個 c[ i ][ j ]的大小,所以時間為 mn;
空間複雜度:需要儲存c[ i ][ j ],所以空間為 mn。
#coding:utf-8
deflcs
(i,j,x,b,out):
#得到最長子序列
if i == -1
or j == -1:
return
if b[i][j] == 1:
print i,j
lcs(i-1,j-1,x,b,out)
elif b[i][j] == 2:
lcs(i-1,j,x,b,out)
elif b[i][j] == 3:
lcs(i,j-1,x,b,out)
print out
return out
deflcslength
(x,y):
#計算最長子序列的長度,以及位置i,j
m = len(x)
n = len(y)
c = {}
c[-1] = {}
b = {}
for i in range(m):
c[i] = {}
c[i][-1] = 0
for j in range(n):
c[-1][j] = 0
for k in range(m):
b[k] = {}
for i in range(m): #外迴圈
for j in range(n): #內迴圈
if x[i] == y[j]:
c[i][j] = c[i-1][j-1] + 1
b[i][j] = 1
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = 2
else:
c[i][j] = c[i][j-1]
b[i][j] = 3
print i,j,c[i][j]
print c[m-1][n-1]
out =
out = lcs(m-1,n-1,x,b,out)
print out[::-1]
x = raw_input().split()
y = raw_input().split()
lcslength(x, y)
問題描述:給定n種物品和一揹包,物品i的重量是wi,其價值為vi,揹包的容量為c。問應如何選擇裝入揹包的物品(物品不能分割),使得裝入揹包中物品的總價值最大?
遞迴定義最優值,逆序得到最優解:
m( i , j )表示最優值總價值,wi 表示第 i 件物品的重量, vi 表示第 i 見物品的價值,i 表示剩下的還可以選擇是否裝入的物品有 i,i+1,i+2,….,n ; j 表示剩餘的空間;
從上往下依次情況是:
(1)裝到第 i 見物品時,當 剩餘空間大於等於這件物品的重量,意思是可以裝下這件物品,那麼可以選擇裝還是不裝,取決於兩種情況的價值;
(2)裝到第 i 見物品時,當 剩餘空間小於這件物品的重量,裝不下這件物品;
(3)第n 件物品,如果能裝下,就裝入;
(4)第n 件物品,如果不能裝下,就不裝了;
時間複雜度:需要計算每個 m[ i ][ j ]的大小,所以時間為 num*c;
空間複雜度:需要儲存m[ i ][ j ],所以空間為 num*c。
#coding:utf-8
deftraceback
(num,m,w,c):
x = {}
for i in range(num-1):
if m[i][c] == m[i+1][c]:
x[i] = 0
#沒裝else:
x[i] = 1
c -= w[i]
if m[num-1][c] > 0:
x[num-1] = 1
else:
x[num-1] = 0
print x
value = 0
for j in x:
if x[j] == 1:
value += v[j]
else:
continue
print
"總價值",value
defbackpack
(num,v,w,c):
print num,v,w,c
jmax = min(w[num-1]-1,c)
m = {}
m[num-1] = {}
for j in range(jmax+1):
m[num-1][j] = 0
for j in range(w[num-1],c+1):
m[num-1][j] = v[num-1]
i = num-2
for k in range(num-1):
m[k] = {}
while i > 0:
jmax = min(w[i]-1,c)
for j in range(jmax+1):
m[i][j] = m[i+1][j]
for j in range(w[i],c+1):
m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i])
i -= 1
m[0][c] = m[1][c]
if (c > w[0]):
m[0][c] = max(m[1][c],m[1][c-w[0]+v[0]])
traceback(num,m,w,c)
num = raw_input(u"請輸出帶裝入的物品個數:")
num = int(num)
v = raw_input("請輸入每個物品的價值:")
v = [int(i) for i in v.split()]
w = raw_input("請輸入每個物品的重量:")
w = [int(i) for i in w.split()]
c = raw_input("請輸入揹包的容量:")
c = int(c)
backpack(num,v,w,c)
請輸出帶裝入的物品個數:5
請輸入每個物品的價值:1 2 3 4 5
請輸入每個物品的重量:1 2 3 4 5
請輸入揹包的容量:10
5 [1, 2, 3, 4, 5]
[1, 2, 3, 4, 5] 10
總價值 10
演算法 動態規劃演算法
動態規劃法基本思想 將原問題分解為相似的子問題,在求解的過程中通過子問題的解求出原問題的解。著名的應用例項有 求解最短路徑問題,揹包問題,專案管理,網路流優化等。個人對動態規劃的理解,主要就是避免重複計算。就是那些曾經發生過的事情,曾經計算過的值先儲存下來,然後再次遇到相同的子問題的時候,直接用儲存...
演算法 動態規劃演算法
動態規劃法基本思想 將原問題分解為相似的子問題,在求解的過程中通過子問題的解求出原問題的解。著名的應用例項有 求解最短路徑問題,揹包問題,專案管理,網路流優化等。個人對動態規劃的理解,主要就是避免重複計算。就是那些曾經發生過的事情,曾經計算過的值先儲存下來,然後再次遇到相同的子問題的時候,直接用儲存...
演算法 動態規劃演算法
背 包問題 有乙個揹包,容量為 4磅 現有如下物品 物品 重量 吉他 g 1 1500 音響 s 4 3000 電腦 l 3 2000 1 要求達到的目標為裝入的揹包的總價值最大,並且重量不超出 2 要求裝入的物品不能重複 動態規劃的核心思想是把原來的問題分解成子問題進行求解,也就是分治的思想。但是...