揹包問題

揹包問題其中就是動態規範中的一大種類
揹包問題最基礎的內容分爲01揹包、完全揹包、多重揹包

01揹包: 有N件物品和一個容量爲V的揹包。(每種物品均只有一件)第i件物品的費用是 c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大
完全揹包: 有N種物品和一個容量爲V的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大
多重揹包: 有N種物品和一個容量爲V的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大

對於01揹包,也就是對於每個物品,我們只有“選”與“不選”兩個選項。所以代碼給下去,很容易理解

for(int i=1;i<=n;i++)//第一層枚舉每個物品
    for(int j=T;j>=w[i];j--)//第二層枚舉當前的花費
        f[j]=max(f[j],f[j-w[i]]+p[i]);//對於每個花費,有"選"這個物品和"不選"這個物品的抉擇,取最優的決策

那麼可能有人問,爲什麼第二層循環要從大到小,因爲這是01揹包,每個物品只有一個。如果從小到大,那麼花費小的先被更新,花費大的就會用到前面已經更新的結果。這樣就影響了花費大的結果,具有後效性
“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”
對於完全揹包,也就是每個物品可以取無限個,那麼其實我們的代碼改動一丟丟就好,先放代碼:

    for(int i=1;i<=n;i++)//第一層枚舉每個物品
        for(int j=w[i];j<=T;j--)//第二層枚舉當前的花費
            f[j]=max(f[j],f[j-w[i]]+p[i]);

沒錯!你可能發現了,我們只是把原來的代碼的第二重循環從大到小改成了從小到大。你可能會問:剛纔不是說了一樣就具有後效性了嗎!?其實不然,注意我前面說過的一句話:“花費大的就會用到前面已經更新的結果”。沒錯,完全揹包的特點就是可以選0個,1個,2個….∞個。所以我們每次更新都要用到前面的結果做爲基礎來更新。換句話說,就是:“在考慮“加選一件第i種物品”這種策略時,卻正需要一個可能已選入第i種物品的子結果”
“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”
對於多重揹包,也就是每個物品最多可以取n[i]件。其實它跟完全揹包有些類似,一個是去無線個,一個是取有限個,方法大同小異。如果拿它跟01揹包相比其實就是多了一個第三層循環,用來枚舉是買0個好?還是1個好?還是3個好呢。總而言之,先放代碼

for(int i=1;i<=n;i++)
    for(int j=T;j>=k*w[i];j--)
        for(int k=0;k<=n[i];k++)
            f[j]=max(f[j],f[j-k*w[i]]+k*p[i]);

總結完畢!如果追求卓越,可以看看關於揹包問題的優化↓
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章