基本思想
將一個問題分爲子問題遞歸求解,且將中間結果保存以避免重複計算。通常可以求得子問題的最優解,且最優解的局部也是最優的。求解過程產生多個決策序列,下一步總是依賴上一步的結果,自底向上的求解。
1.揹包問題
0-1揹包問題
有n件物品和一個容量爲 v的揹包,放入第i件物品的空間消耗是
基本思路:
定義子問題:f[i][j]表示將前i個物品放入容量爲j的揹包中。
求解時只需考慮第i個物品放入或者不放入兩種可能
則有狀態轉移方程:f[i][j] = max{f[i-1][j],f[i-1][j-
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])
關於初始化:
如果要求揹包必須裝滿,那麼初始化因爲
2.完全揹包問題
同樣是有n種物品,一個容量爲v的包,但是每種物品可以無限件使用,放入第i種物品費用是
思路:轉化爲0-1揹包問題,第i件物品可以無限放,但最多也就放
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]);
}