動態規劃概述

在之前的裝配線調度矩陣鏈乘法的問題上,大體上已經對如何去解決一個動態規劃問題的步驟有了一定的瞭解。但是,對於什麼問題可以用動態規劃求解,動態規劃的問題有什麼明顯的特徵,或許並不是很清晰,所以下文主要簡單的討論動態規劃問題的主要要素,並且討論一種不同的方法,稱爲備忘錄,以充分利用重疊子問題的性質。

最優子結構:
什麼是最優子結構?和最長公共子序列問題中所提到的一樣,如果一個問題的一個最優解包含了子問題的最優解,那麼該問題就具有最優子結構,那麼該問題就可能可以使用動態規劃的問題求解(當然貪心策略也是有可能的),而動態規劃的解決方式就是通過對子問題的最優解來構造問題的一個最優解。
那該怎麼尋找最優解?其實有一種共同的模式:
1.問題的一個解可以是做一個選擇,做這樣的選擇可以得到一個或多個有待解決的子問題。例如在最長公共子序列問題中的前綴的選擇,或者選擇一個下標來分解矩陣鏈。
2.假設對一個給定的問題,已知的是一個可以導致最優解的選擇。不必關心如何確定這個選擇,儘管假設是已知的。

3.在已知這個選擇後,要確定哪些子問題會隨之發生,以及如何最好的描述所得到的的子問題的空間。

4.利用一種‘剪貼’技術,來證明在問題的一個最優解中,使用的子問題的解本身也是最優的。通過假設每一個子問題的解不是最優的,然後導出矛盾,就可以做到這一點。

在描述子問題空間時,可以遵循一條經驗規則,就是儘量保持這個空間簡單,然後在必要時去擴充。

最優子結構在問題域中以兩種方式變化

1)有多少個子問題被使用在原問題的一個最優解中

2)在決定一個最優解中使用哪些子問題時有多少個選擇

在裝配線調度的問題中,一個最優解只有一個子問題,但是爲了確定最優解有兩種不同的選擇。在矩陣鏈乘法中,有兩個子問題,就是在k處分裂出去的兩遍,但是有j-i種不同的選擇。

動態規劃以自底向上的方式來利用最優子結構,首先找到子問題的最優解,解決子問題,然後再解決原問題。尋找問題的最優解需要在子問題中做出選擇,用哪一個子問題來求解問題。問題解決的代價通常是子問題的代價加上選擇的代價。

一些細微之處

要注意不能應用最優子結構的時候,就一定不能假設它能夠使用。考慮下面兩個問題,已知一個有向圖G=(V,E)和節點u,v屬於V。

無權最短路徑:找出一條從u到v的包含最少邊數的路徑。

無權最長簡單路徑:找出一條從u到v的包含最多邊數的簡單路徑。

對於無權最短路徑來說,的確是具有最優子結構的特徵。從u到v的最短無權路線上假設包含的頂點稱爲w,那麼從u到w的路徑以及從w到v的路徑必然也是最短的,這點可以通過剪貼法證明,假設從u到w有更短的路徑,那麼將那條路徑貼過來可以構成更短的路徑,這與假設不符。但對於無權最長簡單路徑的問題就不是這樣了,假設從u到v的最長簡單路徑中包含節點w,那麼從u到w的路徑必然不是最長的,因爲從u到w可以先到v那裏轉一圈然後到w,這樣的話路線就明顯增長了。所以對於最長簡單路徑來說,不僅沒有最優子結構的性質,而且無法通過子問題的解來構造原問題的解。事實上,這個問題是NP完全的,就是無法通過多項式時間內解決。

那麼爲什麼最長路徑的子結構和最短路徑的子結構有如此的不同,簡單地說就是因爲子問題的獨立性,所謂子問題獨立,就是一個子問題的求解不會影響到另一個子問題的求解。看下圖的例子:要尋找從q到t的最長簡單路徑有兩個子問題,就是找出從q到r以及從r到t的最長簡單路徑,但對於從q到r,我們可以選擇q->s->t->r作爲最長的簡單路徑,但是一旦選擇了這樣,另一個子問題就會無法解答,因爲第二個子問題的資源已經被第一個子問題使用過了,假設再次使用的話合併將會得到一個非簡單的路徑。


那爲什麼在尋找最短路徑時子問題就是獨立的呢?那是因爲子問題本來就沒有共享資源。如果w在u->v的最短路徑上,那麼我們就可以通過u->w和w->v的最短路徑來產生一條u->v的最短路徑。假設某個頂點x同時出現在兩條最短路徑上,那麼可以把第一條最短路徑分解成u->x->w,第二條分解成w->x->v,這時候我們發現,直接u->x->v的路徑要比u->w->v快兩條路徑,這與假設相矛盾。

重疊子問題。

動態規劃的第二個規則就是要求子問題的規模要很小,也就是說用遞歸算法可以重複的求解同樣的子問題而不是不斷的生成新的子問題。當一個遞歸算法不斷調用同一個問題時,我們就稱之爲最優問題包含重疊子問題。動態規劃就是每個子問題求解一次,然後把結果放在一個表中。

重新回顧一下矩陣鏈乘法的問題,在解決較高行子問題時,要反覆查看較低行的子問題。例如,m[3,4]被引用了4次:m[2,4],m[1,4],m[3,5],m[3,6]。如果每一次都被重新計算,那麼代價就太大了。爲了確定這一點,觀察一下直接使用遞歸式的程序:


將會產生如下的地歸樹:


這樣將會產生指數形式的子問題的數量,但如果使用了重疊子問題的方法,那麼只會產生n^2個子問題。

重新構造一個最優解

通常我們是把子問題所作出的選擇保存在一個表格中,這樣就可以隨時查詢信息了。

做備忘錄

當然,直接使用簡單的遞歸形式也是可以進行動態規劃的,備忘錄就是一種特殊的動態規劃方式,爲每個子問題的解在表中記錄一個表項。開始時,這個表項有一個特殊值,表示這個地方有待填入數值,當第一次訪問這個子問題時,計算這個子問題然後把數據填入表項,以後的訪問中只需要簡單的訪問這個表項而不需要重新進行計算了。這就有點像是標誌flag。下面是使用備忘錄版本的矩陣鏈的乘法:





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章