動態規劃中當前的狀態往往依賴於前一階段的狀態和前一階段的決策結果。例如我們知道了第i個階段的狀態si以及決策ui,那麼第i+1階段的狀態si+1也就確定了。所以解決動態規劃問題的關鍵就是確定狀態轉移方程,一旦狀態轉移方程確定了,那麼我們就可以根據方程式進行編碼。
在前面的文章《動態規劃-開篇》講到了如何設計乙個動態規劃演算法,有以下四個步驟:
1、刻畫乙個最優解的結構特徵。
2、遞迴地定義最優解的值。
3、計算最優解的值,通常採用自底向上的方法。
4、利用計算出的資訊構造乙個最優解。
對於確定狀態轉移方程就在第一步和第二步中,首先要確定問題的決策物件,接著對決策物件劃分階段並確定各個階段的狀態變數,最後建立各階段的狀態變數的轉移方程。
例如用dp[i]表示以序列中第i個數字結尾的最長遞增子串行長度和最長公共子串行中用dp[i][j]表示的兩個字串中前 i、 j 個字元的最長公共子串行,我們就是通過對這兩個數字量的不斷求解最終得到答案的。這個數字量就被我們稱為狀態。狀態是描述問題當前狀況的乙個數字量。首先,它是數字的,是可以被抽象出來儲存在記憶體中的。其次,它可以完全的表示乙個狀態的特徵,而不需要其他任何的輔助資訊。最後,也是狀態最重要的特點,狀態間的轉移完全依賴於各個狀態本身,如最長遞增子串行中,dp[x]的值由 dp[i](i < x)的值確定。若我們在分析動態規劃問題的時候能夠找到這樣乙個符合以上所有條件的狀態,那麼多半這個問題是可以被正確解出的。所以說,解動態規劃問題的關鍵,就是尋找乙個好的狀態。
下面對這幾天的學習總結一下,將我遇到的各種模型的狀態轉移方程彙總如下:
假設兩個字串為str1和str2,它們的長度分別為n和m。d[i][j]表示str1中前i個字元與str2中前j個字元分別組成的兩個字首字串的最長公共長度。這樣就把長度為n的str1和長度為m的str2劃分成長度為i和長度為j的子問題進行求解。狀態轉移方程如下:
dp[0][j] = 0; (0<=j<=m)
dp[i][0] = 0; (0<=i<=n)
dp[i][j] = dp[i-1][j-1] +1; (str1[i] == str2[j])
dp[i][j] = 0; (str1[i] != str2[j])
因為最長公共子串要求必須在原串中是連續的,所以一但某處出現不匹配的情況,此處的值就重置為0。
詳細**請看最長公共子串。
區分一下,最長公共子串行不同於最長公共子串,序列是保持子串行字串的下標在str1和str2中的下標順序是遞增的,該字串在原串中並不一定是連續的。同樣的我們可以假設dp[i][j]表示為字串str1的前i個字元和字串str2的前j個字元的最長公共子串行的長度。狀態轉移方程如下:
dp[0][j] = 0; (0<=j<=m)
dp[i][0] = 0; (0<=i<=n)
dp[i][j] = dp[i-1][j-1] +1; (str1[i-1] == str2[j-1])
dp[i][j] = max; (str1[i-1] != str2[j-1])
詳細**請看最長公共子串行。
因為兩者的思路都是一樣的,所以只給出最長遞增子串行的狀態轉移方程。假設有序列,我們求其最長遞增子串行長度。按照遞推求解的思想,我們用f[i]代表若遞增子串行以ai結束時它的最長長度。當 i 較小,我們容易直接得出其值,如 f[1] = 1。那麼,如何由已經求得的 f[i]值推得後面的值呢?假設,f[1]到f[x-1]的值都已經確定,注意到,以ax 結尾的遞增子串行,除了長度為1的情況,其它情況中,ax都是緊跟在乙個由 ai(i < x)組成遞增子串行之後。要求以ax結尾的最長遞增子串行長度,我們依次比較 ax 與其之前所有的 ai(i < x), 若ai小於 ax,則說明ax可以跟在以ai結尾的遞增子串行之後,形成乙個新的遞 增子序列。又因為以ai結尾的遞增子串行最長長度已經求得,那麼在這種情況下,由以 ai 結尾的最長遞增子串行再加上 ax 得到的新的序列,其長度也可以確定,取所有這些長度的最大值,我們即能得到 f[x]的值。特殊的,當沒有ai(i < x)小 於ax, 那麼以 ax 結尾的遞增子串行最長長度為1。 即f[x] = max,求子序列的和最大問題,我們用dp[i]表示以ai結尾的子串行的最大和。
dp[1] = a1; (a1>=0 && i == 1)
dp[i] = dp[i-1]+ai; (ai>=0 && i>=2)
dp[i] = 0; (dp[i-1] + ai <=0 && i>=2)
詳細**請看最大子串行的和。
給定乙個陣列data[n][m]構成乙個數塔求從最上面走到最低端經過的路徑和最大。可以假設dp[i][j]表示走到第i行第j列位置處的最大值,那麼可以推出狀態轉移方程:
dp[i][j] = max + data[i][j];
for(i=n-1;i>=1;i--)+s[i][j]}}view code
這是乙個經典的動態規劃問題,另外在貪心演算法裡也有揹包問題,至於二者的區別在此就不做介紹了。
假設有n件物品和乙個容量為v的揹包。第i件物品的體積是v[i],價值是c[i],將哪些物品裝入揹包可使價值總和最大?
每一種物品都有兩種可能即放入揹包或者不放入揹包。可以用dp[i][j]表示第i件物品放入容量為j的揹包所得的最大價值
,則狀態轉移方程可以推出如下:
dp[i][j]=max;
for (int i = 1;i <= n;i++) //view code列舉物品
} }
可以參照動態規劃 - 0-1揹包問題的演算法優化、動態規劃-完全揹包問題、動態規劃-多重揹包問題
例如矩陣鏈,它們的維數分別為10*100,100*5,5*50,那麼如果順序相乘即((a1a2)a3),共需10*100*5 + 10*5*50 = 7500次乘法,如果按照(a1(a2a3))順序相乘,卻需做100*5*50 + 10*100*50 = 75000次乘法。兩者之間相差了10倍,所以說矩陣鏈的相乘順序也決定了計算量的大小。
我們用利用動態規劃的方式(dp[i][j]表示第i個矩陣至第j個矩陣這段的最優解,還有對於兩個矩陣a(i,j)*b(j,k)則需要i*j*k次乘法),推出狀態轉移方程:
dp[i][j] = 0; (i ==j,表示只有乙個矩陣,計算次數為0)
dp[i][j] = min; (i
dp[1][n]即為最終求解.
#define maxsize 100view codeint dp[maxsize][maxsize];//
儲存最小的就算次數
int s[maxsize][maxsize];//
儲存斷點,用在輸出上面
inti, j, tmp;
for (int l = 2; l <= n; l++)
}}}//
遞迴呼叫輸出
void output(int i, int
j)
else
}
如有錯誤的地方或者本人理解錯的地方,請指出,共同進步!!!
動態規劃 狀態轉移方程練習
1.給定乙個陣列penny表示可用的零錢都有哪些面值,再給定乙個整數n表示penny的長度,再給定乙個整數m表示需要換零錢的整錢面值,輸出換錢的方案有幾種。樣例 1,2,4 3,3 返回 2 這是乙個比較簡單的動態規劃問題,dp為狀態陣列,只使用1的時候有一種方法 3 1 1 1 使用1 2的時候有...
各種動態規劃經典模型
1.lis 方法1.n 2 動態規劃 方法2.對上面的動態規劃優化後,發現決策是可以簡單化的,就是一些決策可以直接捨棄掉,對應到搜尋就是剪枝,用二分查詢搞到 n log n 2.lcs 方法1.時間空間均為 n 2 的動態規劃。記 f i,j 為匹配到a的i和b的j.上面可以壓縮一維空間。3.lci...
動態規劃經典問題
from 實現在 維基百科對動態規劃的定義 動態規劃 英語 dynamic programming,簡稱dp 是一種在數學 電腦科學和經濟學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題 1 和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於...