1. 程式人生 > >第二講 完全背包問題(對背包九講的學習)

第二講 完全背包問題(對背包九講的學習)

而已 line code 多少 成了 直接 基礎 基本 修改

學習自:背包九講

題目

有N種物品和一個容量為V的背包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入背包可使這些物品的費用總和不超過背包容量,且價值總和最大。

基本思路:

完全背包和01背包的區別是一個物品可以被拿無限次,我們之前01背包是拿或者不拿的max,比較,然後我們處理完全背包的時候每個物品拿多少次就好了

每個物品最優拿法=max(不拿,拿一個,拿兩個,...,拿n個),拋出個問題,n難道是無限嗎?顯然不是,大前提是背包總空間或者說處理到第i個物品時剩余空間有限

如果說當前空間最多只能拿n個,那我們的max函數就比較到這個物品拿n個時候就好了

這樣一來,無限的問題被我們用背包總空間的限制條件處理成了一個動態的有限問題

其實也算是完全背包轉多重背包

這樣來就有了第一個遞推式

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}

一個簡單有效的優化

開始前可以來一次時間復雜度為O(n^2)的優化,就是假如有物品a,b

a比b占用空間多並且比b價值少,那我們可以直接排除掉不劃算的物品a

對於隨機生成的數據,這樣子還是可以優化一部分的

轉化為01背包問題求解

一個物品最多可以拿V/c[i]次,這一步把問題由完全背包轉移到了多重背包

下面貼一張我自己寫的文字的截屏

技術分享圖片

技術分享圖片

最優方法,時間復雜度O(n*V),空間復雜度為一維數組

使用了滾動數組,並且只是01背包代碼的修改而已

回想一下我們學01背包滾動數組版本的時候,是不是要求數組第二維的j一定要從後往前,從大到小來遍歷,就是為了防止新數據被新數據覆蓋

我們只允許舊數據被新數據覆蓋(拿一次還是不拿),那麽新數據被新數據覆蓋在實際層面怎麽理解呢,就是(拿j次還是拿j-1次)

所以接下來我們在01背包代碼的基礎上讓第二維的j從小到大,從前往後

如果說新數據覆蓋新數據更好,那麽我就給你覆蓋,也就是如果已經拿了幾個這種物品了,如果再拿幾個會更好,那我就給你拿

for(ll i=1;i<=n;i++)
        
for(ll j=c[i];j<=V;j++) { f[j]=max(f[j],f[j-c[i]]+w[i]); }

感謝老師教的這種層面理解方法,通俗易懂

第二講 完全背包問題(對背包九講的學習)