動態規劃系列

基本思想

將一個問題分爲子問題遞歸求解,且將中間結果保存以避免重複計算。通常可以求得子問題的最優解,且最優解的局部也是最優的。求解過程產生多個決策序列,下一步總是依賴上一步的結果,自底向上的求解。

1.揹包問題

0-1揹包問題

有n件物品和一個容量爲 v的揹包,放入第i件物品的空間消耗是ci ,得到的價值是wi 。求解將哪些物品裝入揹包可使價值總和最大。

基本思路:
定義子問題:f[i][j]表示將前i個物品放入容量爲j的揹包中。
求解時只需考慮第i個物品放入或者不放入兩種可能
則有狀態轉移方程:f[i][j] = max{f[i-1][j],f[i-1][j-ci ]+wi

f[0,0...v] = 0
for i <- 1 to n
    for j <- 0 to v
        if(v < c[i]) continue;//放不下第i個物品
        f[i][j] = max(f[i-1][j],f[i-1][v-c[i]]+w[i])

空間優化:
由於 i 在從0 到 n的過程中,每次只以i-1的狀態進行計算,我們可以考慮只用一維數組節省空間,即使用f[0…v]來保存狀態,但是根據我們的狀態轉移方程,f[i][j] 是由f[i-1][j]與f[i-1][j-c[i]]來決定的,也就是說考慮往容量大小爲j的包裏放東西時,取決於i-1的狀態時,j-c[i]大小容量的最優解。
j-c[i] < j, 那麼在更新j狀態的值時,j-c[i]狀態的值要沒有變過,所以j要從大到小更新。

f[0...v] <- 0
for i <- 1 to n
    for j <- v to c[i]
        f[j] = max(f[j],f[j-c[i]]+w[i])

關於初始化:
如果要求揹包必須裝滿,那麼初始化因爲 , 因爲如果不要求揹包裝滿,那麼每個子問題必有一個解,什麼都不裝爲0,但如果要求必須裝滿就可能存在無解的異常狀態,用 表示

2.完全揹包問題

同樣是有n種物品,一個容量爲v的包,但是每種物品可以無限件使用,放入第i種物品費用是ci ,價值是wi ,解價值最大的放法
思路:轉化爲0-1揹包問題,第i件物品可以無限放,但最多也就放v/ci 件,那麼f[i][j]狀態更新時的狀態轉移方程可以爲:

f[i][j]=max(f[i1][vkc[i]]+kw[i]),0<=kc[i]<=v

3.最長公共子串

給定兩個字符串str1,str2,求最長公共子串
思路:
在比較str1[i]與str2[j]的時候,即以str1[i],str2[j]結尾的子串的最長公共子串,如果str1[i]==str2[j], 結果爲str1[i-1]與str2[j-1]的最長公共子串加1,如果用dp[i][j]表示以str1[i],str2[j]結尾的兩個字符串的最長公共子串,那麼狀態轉移方程可以寫爲:

if(str1[i] == str2[j]){
    dp[i][j] = dp[i-1][j-1]+1;
}
else dp[i][j] = 0;

4.最長公共子序列

最長公共子序列與最長公共子串不同,可以不連續
那麼在狀態轉移方程中,在str1[i]與str2[j]如果不等,dp[i][j] 不是爲0,而是等於max(dp[i-1][j],dp[i][j-1], 如下:
狀態記錄二維數組大小可以爲dp[n1+1][n2+1], 留dp[0][0]作爲初始狀態

if(str1[i] == str2[j]){
    dp[i][j] = dp[i-1][j-1]+1;
}
else{
    dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}

待續

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