1. 程式人生 > 其它 >揹包九講(4)

揹包九講(4)

揹包九講(4)

多重揹包問題 II

有 N 種物品和一個容量是 V 的揹包。

第 ii 種物品最多有 si 件,每件體積是 vi,價值是 wi。

求解將哪些物品裝入揹包,可使物品體積總和不超過揹包容量,且價值總和最大。
輸出最大價值。

輸入格式

第一行兩個整數,N,V,用空格隔開,分別表示物品種數和揹包容積。

接下來有 N 行,每行三個整數 vi,wi,si,用空格隔開,分別表示第 ii 種物品的體積、價值和數量。

輸出格式

輸出一個整數,表示最大價值。

資料範圍

0<N≤1000
0<V≤2000
0<vi,wi,si≤2000

提示:

本題考查多重揹包的二進位制優化方法。

輸入樣例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

輸出樣例:

10

思路:
本題物品數量和體積都過大,因此要去優化,一般可以考慮將每個物品拆分開來,這樣就是單純的01揹包問題,但是全拆分為1份複雜度過大,因此使用二進位制來優化,所謂二進位制優化就是每次拆除2的倍數,先拆1再拆2,4...當無法拆時,停止即可,這樣需要logS,時間複雜度不會過大,可以接受

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 2020;

int f[N];

struct good{
    int v;
    int w;
};

int main(){
    int n,m;
    cin>>n>>m;
    vector<good>goods;
    //將每種物品拆分(利用2進位制拆分)
    for(int i=0;i<n;i++){
        int v,w,s;
        cin>>v>>w>>s;
        for(int k=1;k<=s;k*=2){
            s-=k;
            goods.push_back({v*k,w*k});
        }
        //拆完 有剩餘 放入
        if(s>0) goods.push_back({v*s,w*s});
    }
    //拆分完後 就優化成了01揹包問題 使用01揹包模板即可
    //列舉每個物品
    for(auto good:goods){
        //體積從大到小
        for(int j=m;j>=good.v;j--){
            f[j]=max(f[j],f[j-good.v]+good.w);
        }
    }
    cout<<f[m];
}