1. 程式人生 > >動態規劃演算法祕籍

動態規劃演算法祕籍

本文來自通俗易懂演算法入門書《趣學演算法》。

動態規劃是1957年理查德·貝爾曼在《Dynamic Programming》一書中提出來的,八卦一下,這個人可能有同學不知道,但他的一個演算法你可能聽說過,他和萊斯特·福特一起提出了求解最短路徑的Bellman-Ford 演算法,該演算法解決了Dijkstra演算法不能處理負權值邊的問題。

Dynamic Programming,這裡的Programming不是程式設計的意思,而是指一種表格處理法。我們把每一步得到的子問題結果儲存在表格裡,每次遇到該子問題時不需要再求解一遍,只需要查詢表格即可。

4.1.1 演算法思想

動態規劃也是一種分治思想,但與分治演算法不同的是,分治演算法是把原問題分解為若干子問題,自頂向下,求解各子問題,合併子問題的解從而得到原問題的解。動態規劃也是把原問題分解為若干子問題,然後自底向上,先求解最小的子問題,把結果儲存在表格中,在求解大的子問題時,直接從表格中查詢小的子問題的解,避免重複計算,從而提高演算法效率。

4.1.2 演算法要素

什麼問題可以使用動態規劃呢?我們首先要分析問題是否具有以下兩個性質:

(1) 最優子結構

最優子結構性質是指問題的最優解包含其子問題的最優解。最優子結構是使用動態規劃的最基本條件,如果不具有最優子結構性質就不可以使用動態規劃解決。

(2) 子問題重疊

子問題重疊是指在求解子問題的過程中,有大量的子問題是重複的,那麼只需要求解一次,然後把結果儲存在表中,以後使用時可以直接查詢,不需要再次求解。子問題重疊不是使用動態規劃的必要條件,但問題存在子問題重疊更能夠充分彰顯動態規劃的優勢。

什麼問題可以使用動態規劃呢?我們首先要分析問題是否具有以下兩個性質:

(1) 最優子結構

最優子結構性質是指問題的最優解包含其子問題的最優解。最優子結構是使用動態規劃的最基本條件,如果不具有最優子結構性質就不可以使用動態規劃解決。

(2) 子問題重疊

子問題重疊是指在求解子問題的過程中,有大量的子問題是重複的,那麼只需要求解一次,然後把結果儲存在表中,以後使用時可以直接查詢,不需要再次求解。子問題重疊不是使用動態規劃的必要條件,但問題存在子問題重疊更能夠充分彰顯動態規劃的優勢。

4.1.1 解題祕籍

遇到一個實際問題,如何採用動態規劃來解決呢?

(1) 分析最優解的結構特徵。

(2) 建立最優值的遞迴式。

(3) 自底向上計算最優值,並記錄。

(4) 構造最優解。

本章通過8個例項,講解了動態規劃的解題過程。動態規劃求解最優化問題時需要考慮兩個性質:最優子結構和子問題重疊,只要滿足最優子結構性質就可以使用動態規劃,如果還具有子問題重疊,則更能彰顯動態規劃的優勢。判斷可以使用動態規劃後,就可以分析其最優子結構特徵,找到原問題和子問題的關係,從而得到最優解遞迴式。然後按照最優解遞迴式自底向上求解,採用備忘機制(查表法)有效解決子問題重疊,重複的子問題不需要重複求解,只需查表即可。

動態規劃的關鍵:

(1)最優子結構判定

a. 作出一個選擇;

b. 假定已經知道了哪種選擇是最優的;

例如矩陣連乘問題,我們假設已經知道在第k個矩陣加括號是最優的,即(AiAi+1…Ak)(Ak+1Ak+2…Aj)。

c. 最優選擇後會產生哪些子問題;

例如矩陣連乘問題,我們作出最優選擇後產生兩個子問題:(AiAi+1…Ak),(Ak+1Ak+2…Aj)。

d. 證明原問題的最優解包含其子問題的最優解。

通常使用“剪下—貼上”反證法。證明如果原問題的解是最優解,那麼子問題的解也是最優解。反證:假定子問題的解不是最優解,那麼就可以將它“剪下”掉,把最優解“貼上”進去,從而得到一個比原問題最優解更優的解,這與前提原問題的解是最優解矛盾。得證。

例如:矩陣連乘問題,c=a+b+d,我們只需要證明如果c是最優的,則a和b一定是最優的(即原問題的最優解包含子問題的最優解)。

反證法:如果a不是最優的,(AiAi+1…Ak) 存在一個最優解aˊ,aˊ<a,那麼,aˊ+b+d<c,這與假設c是最優的矛盾,因此如果c是最優的,則a一定是最優的。同理可證b也是最優的。因此如果c是最優的,則a和b一定是最優的。因此,矩陣連乘問題具有最優子結構性質。

(2)如何得到最優解遞迴式

a.分析原問題最優解和子問題最優解的關係;

例如矩陣連乘問題,我們假設已經知道在第k個矩陣加括號是最優的,即(AiAi+1…Ak)(Ak+1Ak+2…Aj)。作出最優選擇後產生兩個子問題:(AiAi+1…Ak),(Ak+1Ak+2…Aj)。如果我們用m[i][j]表示AiAi+1…Aj矩陣連乘的最優解,那麼兩個子問題:(AiAi+1…Ak),(Ak+1Ak+2…Aj)對應的最優解分別是m[i][k],m[k+1][j]。剩下的只需要考察(AiAi+1…Ak)和(Ak+1Ak+2…Aj)的結果矩陣相乘的乘法次數了。兩個結果矩陣相乘的乘法次數是pi*pk+1*qj。

因此,原問題最優解和子問題最優解的關係:m[i][j]= m[i][k]+m[k+1][j]+ pi*pk+1*qj

b.考察有多少種選擇;

實質上,我們並不知道哪種選擇是最優的,因此就需要考察有多少種選擇,然後從這些選擇中找到最優解。

例如矩陣連乘問題,加括號的位置k(AiAi+1…Ak)(Ak+1Ak+2…Aj),k的取值範圍是{i,i+1,…,j-1},即i≤k<j,那麼我們考察每一種選擇,找到最優值。

c.得到最優解遞迴式。

例如矩陣連乘問題,m[i][j]表示AiAi+1…Aj矩陣連乘的最優解,根據最優解和子問題最優解的關係,並考察所有的選擇,找到最小值就是我們要的最優解。

動態規劃演算法祕籍