1. 程式人生 > >01背包與完全背包

01背包與完全背包

無限 選擇 最大 [] 完全背包 兩種 最大值 體積 但我

01背包
有一個體積為V的背包,有n個物品,每個物品都有體積vi和價值wi,在背包體積範圍內,求能桌下的最大價值。

這個問題中每個物品只能用一次。
設dp[i][j]表示用前i個物品裝體積為j的背包。
那麽第i個物品要麽裝要麽不裝:

1、如果不裝,第i個物品和沒有一樣,dp[i][j]=dp[i-1][j]
2、如果裝,減去第i個物品的體積,加上第i個物品的價值,那麽它還是和沒有一樣。。dp[i][j]=dp[i-1][j-v[i]]+w[i];

我們只需取這兩種方案的最大值,就算是解決了。dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);

時間復雜度是O(V*M),空間也是O(V*M)
其實空間可以優化
註意觀察,可以發現每個狀態dp[i][j]之和dp[i-1][]有關,什麽i-2,i-3都沒用了
我們試著開一個一維的數組dp[M];
一維難道不會覆蓋掉原來的值麽?
會的,但我們優先覆蓋不用的值。怎麽說呢?就是我們每次只會用比j小的地方的值,比j大的地方是不用到的,所以我們只要j從後往前枚舉,就不會沖突了。

dp[j]=max(dp[j],dp[j-v[i]]+w[i]) [j=N->v[i]]

for(int i= 1; i <= n; i++) {
for (int j = m; j >= w[i]; j--) {
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
}
}
完全背包
完全背包就是每種物品有無限個的背包
這個時候我們的狀態轉移方程可以這麽寫:dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]]+w[i]);
看起來好像沒區別啊?!
真的麽?
仔細看看,i-1變成了i
也就是說,選擇了第i個物品後,並不是轉到i-1,因為每個物品有無限個,所以還是轉到了i
狀壓一下,就是
dp[j]=max(dp[j],dp[j-v[i]]+w[i]) 【j=v[i]->N】

唯一的區別就是j枚舉的方向反了過來
for(int i= 1; i<= n; i++) {
for (int j = w[i]; j <= m; j++) {
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
}
}

01背包與完全背包