動態規劃(二)

2021-07-26 15:59:46 字數 2713 閱讀 4095

之前的兩個問題都是用動態規劃方法解決的,那麼什麼情況下需要使用動態規劃呢?適應動態規劃方法求解的最優化問題應該具備的兩個要素:最優子結構和子問題重疊。

用動態規劃方法求解最優化問題的第一步就是刻畫最優解的結構。如果乙個問題的最優解包含其子問題的最優解,就稱此問題具有最優子結構性質。使用動態規劃方法時,我們用子問題的最優解來構造原問題的最優解,因此就要仔細考察最優解中用到的所有子問題。

在發掘最優子結構性質的過程中,遵循了如下的通用模式:

1. 證明問題最優解的第乙個組成部分是做出乙個選擇,做出這次選擇會產生乙個或多個待解的子問題。

2. 對於乙個給定問題,在其可能的第一步選擇中,假定已經知道哪種選擇才會得到最優解,並不關心這種選擇具體是如何得到的,只是假定已經知道了這種選擇。

3. 給定可獲得最優解的選擇後,確定這次選擇會產生哪些子問題,以及如何最好地刻畫子問題空間。

4. 證明作為構成原問題最優解的組成部分,每個子問題的解就是它本身的最優解,可利用反證法證明。

刻畫子問題空間的經驗是:保持子問題空間盡可能簡單,只在必要時才擴充套件它。

對於不同問題領域,最優子結構體的不同體現在兩個方面:

- 原問題的最優解中涉及多少個子問題,以及

- 在確定最優解使用那些子問題時,我們需要考察多少種選擇。

在動態規劃方法種,通常自底向上的使用最優子結構,也就是說,首先求得子問題的最優解,然後求原問題的最優解,在求解原問題過程中,需要在涉及的子問題中做出選擇,選擇得到原問題最優解的子問題,原問題最優解的代價通常就是子問題最優解的代價加上由此次選擇直接產生的代價。

在嘗試使用動態規劃方法時要小心,要注意問題是否具有最優子結構性質。對於乙個無權有向圖來說,無權最短路徑自然可以使用動態規劃方法進行求解,但無權最長簡單路徑就不適用動態規劃方法了,原因是求解乙個子問題時用到了某些資源,導致這些資源在求解其他子問題時不可用。

適合動態規劃方法求解的最優化問題應該具備的第二個性質是子問題空間必須足夠「小」,即問題的遞迴演算法會反覆求解相同的子問題,而不是一直生成新的子問題,一般來講,不同子問題的總數是輸入規模的多項式函式為好,如果遞迴演算法反覆求解相同的子問題,就稱最優化問題具有重疊子問題性質,與之相對的,適合用分治方法求解的問題通常在遞迴的每一步都生成全新的子問題。

凡是乙個問題的自然遞迴演算法的遞迴呼叫樹中反覆出現相同的子問題,而不同子問題的總資料很少時,動態規劃方法都能提高效率。

帶備忘的遞迴演算法為每個子問題維護乙個表項來儲存它的解,每個表項的初值設為乙個特殊值,表示尚未填入子問題的解,當遞迴呼叫過程中第一次遇到子問題時,計算其解,並存入對應表項,隨後每次遇到同乙個子問題,只是簡單的查詢,返回其解。

最長公共子串行問題給定兩個序列x=(x1,x2,•••,xm)和y=(y1,y2,•••,yn),求x和y長度最長的公共子串行。

最優子結構:令x=(x1,x2,•••,xm)和y=(y1,y2,•••,yn)為兩個序列,z=(z1,z2,•••,zk)為x和y的任意最長公共子串行(lcs)。

- 如果xm=yn,則zk=xm=yn且z(k-1)是x(m-1)和y(n-1)的乙個lcs。

- 如果xm≠yn,那麼zk≠xm意味著z是x(m-1)和y的乙個lcs。

- 如果xm≠yn,那麼zk≠yn意味著z是x和y(n-1)的乙個lcs。

定義c[i, j]表示xi和yj的lcs的長度,c[i, j]的取值可以由下面公式表示:

0, (i=0或j=0)

c[i - 1, j - 1] + 1, (i,j > 0且xi=yj)

max(c[i, j - 1], c[i – 1, j]), (i,j > 0且xi≠yi)

通過輔助表b[i, j]來構造最優解,b[i, j]指向的表項對應計算c[i, j]時所選擇的子問題最優解。偽**如下:

lcs_length(x, y)

m = x.length

n = y.length

let b[m + 1, n + 1] and c[m + 1, n + 1] be new array

for i = 1

to m

c[i, 0] = 0

for j = 1

to n

c[0, j] = 0

for i = 0

to m

for j = 1

to n

if x[i] == y[i]

c[i, j] = c[i – 1, j – 1] + 1

b[i, j] = 「↖」

else

if c[i – 1, j] >= c[i, j – 1]

c[i, j] = c[i – 1, j]

b[i, j] = 「↑」

else

c[i, j] = c[i, j – 1]

b[i, j] = 「←」

return c and b

利用b[i, j]中的箭頭進行追蹤列印,實現的偽**如下:

print_lcs(b, x, i, j)

ifi == 0 or j == 0

return

if b[i, j] == 「↖」

print_lcs(b, x, i - 1, j - 1)

print x[i]

else

if b[i, j] == 「↑」

print_lcs(b, x, i - 1, j)

else

print_lcs(b, x, i, j - 1)

動態規劃(二)

本節實現乙個動態規劃問題實現。具體問題見上一節 的第三個栗子。這裡再次簡述 在乙個時刻系統可以觀察到的有兩個量 剩餘資料報數量m以及通道狀態h。因此我們將二者聯合組成系統狀態 m,h 那麼在每乙個時隙系統總共有2 m 1 個狀態。每乙個狀態可能跳轉到下乙個時隙的某乙個或者一些狀態。跳轉判斷條件有 在...

動態規劃(二)

矩陣鏈乘法問題 給定n個矩陣的鏈,矩陣ai的規模為p i 1 pi 1 i n 求完全括號化方案,使得計算乘積a1a2.an所需標量乘法次數最少。比如矩陣鏈相乘,不同的加括號方式會導致不同的計算代價。假定三個矩陣的規模為10 100 100 5 5 50。若按 a1a2 a3 計算,a1a2需要做1...

動態規劃(二)

本次通過兩個簡單的演算法題來進一步練習和理解動態規劃,廢話不多說,來上題吧。給出乙個陣列,如 6,1,1,9,3 在裡面取任意個數,要求所取得數的位置不能相鄰,比如取了第乙個數就不能取第二個數,但是可以取第三第四個數,求取出數之和的最大值。下面來讓我們分析一下這個題,我們可以分解成求每一位的最優解,...