資料結構與演算法之動態規劃演算法及其python實現

2021-08-07 12:30:55 字數 4269 閱讀 4753

動態規劃演算法和分治法類似,都是將帶求解問題分解為若干個子問題,先求解子問題,然後從這些子問題的解得到原問題的答案。與分治法不同的是,動態規劃要用乙個表來記錄所有已解決的子問題的答案。不管該問題是否以後會被用到,只要它被計算過,就將其結果填入表中。在需要時從表中找出答案,避免大量重複計算,從而得到多項式時間演算法。通常按一下幾個步驟設計動態規劃演算法:

(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 要求裝入的物品不能重複 動態規劃的核心思想是把原來的問題分解成子問題進行求解,也就是分治的思想。但是...