可以先看下這篇部落格理解下動態規劃的思想:初識動態規劃
寫在前面的:這篇部落格主要寫的是,乙個容量為v的揹包去裝n個物品能獲得的最優解的問題
問題簡述:現在有乙個揹包,它能容納的最大重量為v,問揹包所能帶走的最大價值是多少?
01揹包:有n個物品,每個物品的重量為w[i],每個物品的價值為h[i]。
[對於每個物品不可以取多次,最多只能取一次,之所以叫做01揹包,0表示不取,1表示取]
多重揹包:有n種物品,每個物品的重量為w[i],每個物品的價值為h[i],每種物品有c[i]個。
完全揹包:有n種物品,每個物品的重量為w[i],每個物品的價值為h[i],每種物品有無限個。
設dp[i][j]表示處理到第i件物品時,容量為j的揹包能獲得的最大價值,處理結束後dp[n][v]就是我們所要求解的值。揹包問題第一層迴圈都是跑的物品總類數(目前我遇到的都是這樣子),一類一類地處理n類物品。當我們處理到第i件物品時,我們知道前i-1件物品在揹包容量為1、2、3、、、n時能獲得的最大價值分別是dp[i-1][1]、dp[i-1][2]、dp[i-1][3]、、、dp[i-1][v]。既然是01揹包,我們對第i件物品就有兩種策略:不取——那就好辦了,容量為j的揹包所能裝的價值在i-1的基礎上不變,就是dp[i-1][j];取——容量為j的揹包就得騰出w[i]的空位放物品i,此時的價值就為dp[i-1][j-w[i]]+h[i],所以dp[i][j]的最優解就是在這兩種情況之間,dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+h[i])。就這樣,跑完第二層迴圈我們就可以得到dp[i][j]的值(j=1、2、3、、、v)。
—注意:我們對第i件物品的處理都是基於前i-1件物品的存放結果的,而前i-1件物品的存放結果第i件物品沒有參與,這也是01揹包問題一維優化的關鍵點。
—其實跑完了之後我們會發現,我們可以得到揹包容量在1~v範圍內的時去裝這n件物品能獲得的最大價值。
—後面的都是根據這個衍生出來的,而且後面完全揹包和多重揹包問題都能轉化成01揹包。
—揹包中有時可以看到乙個小優化,就是w[i]≤
\leq
≤w[j]&&h[i]≥
\geq
≥h[j]是可以直接把j物品去掉,但不常用,(我沒用過/哭笑),因為它不能優化最壞情況的複雜度。
**:
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(j=w[i]
; j<=v; j++
)//二維陣列這裡從w[i]到v,或者從v到w[i]沒有區別
dp[i]
[j]=
max(dp[i-1]
[j],dp[i-1]
[j-w[i]
]+h[i]
);
處理完第i件物品時,dp[j]就表示用容量為j的揹包去裝前i件物品能獲得的最大價值
基於上面說的二維的解法,既然處理第i件物品只與上一層(i-1)有關,那麼我們就可以將二維陣列轉化為一維陣列,轉化的過程中需要考慮乙個問題:怎樣才能保證我們得到的結果的組成中,每件物品只參與了一次。
因為我們還是要處理n件物品,所以第一層迴圈不變(總不可能說物品處理的順序會影響結果吧),然後看第二層迴圈,我們還是要通過第二層迴圈得到dp[i][j]的值(j=1、2、3、、、v),所以我們還是要遍歷w[i]到v,只不過這裡必須從v開始處理到w[i],因為我們處理dp[j]時會用到dp[j-w[i]]的值,而這個
dp[j-w[i]]必須是前i-1件物品參與的結果,不能有第i件物品的參與。如果我們從前往後處理,先處理dp[j-w[i]],在處理dp[j]的時候,構成dp[j-w[i]]最優解的可能也有第i件物品的參與,這樣的話我們就不能保證每件物品值參與了一次。
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(j=v; j>=w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-w[i]
]+h[i]
);
dp[j]的意義和前面一樣,只不過每件物品能取無窮多次
解法:
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(j=w[i]
; j<=v; j++
) dp[j]
=max
(dp[j]
,dp[j-w[i]
]+h[i]
);
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(int k=
1; k<=v/w[i]
; k++
)for
(j=v; j>=w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-w[i]
]+h[i]
);
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(int k=
1; k*w[i]
<=v; k<<=1)
for(j=v; j>=w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-k*w[i]
]+k*h[i]
);
dp[j]的意義還是和前面一樣,每件物品能取有限次
解法:
memset
(dp,0,
sizeof
(dp));
for(i=
1; i<=n; i++
)for
(int k=
1; k<=c[i]
; k++
)for
(j=v; j>=w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-w[i]
]+h[i]
);
for
(int i=
1; i<=n; i++)if
(c[i]
)for
(int j=v; j>=c[i]
*w[i]
; j--
) dp[j]
=max
(dp[j]
,dp[j-c[i]
*w[i]
]+c[i]
*h[i]);
}
加在後面的:對每一道動態規劃題目都思考其方程的意義以及如何得來,加深對動態規劃的理解 揹包 01揹包,完全揹包,多重揹包
哈哈 01揹包 f i v max 完全揹包 f i v max 多重揹包 f i v max include include include include include define maxn 1000 using namespace std int n,cap int w maxn 重量 花...
01揹包 完全揹包 多重揹包
01揹包 zeroonepack 有n件物品和乙個容量為v的揹包,每種物品均只有一件。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。include include includeusing namespace std const int n 1000 10 int ...
01揹包 完全揹包 多重揹包
01揹包 zeroonepack 有n件物品和乙個容量為v的揹包。每種物品均只有一件 第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。完全揹包 completepack 有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c i 價值是w i 求...