多重背包問題
一個背包,承量有限為W,有n種物體,第i種物體,價值Vi,占用重量為 Wi,且有Ci件,選擇物品若干放入背包,使得總重量不超過背包的承重。總價值最大?
輸入
第1行,2個整數,N和W中間用空格隔開。N為物品的種類,W為背包的容量。(1 <= N <= 100,1 <= W <= 50000) 第2 - N + 1行,每行3個整數,Wi,Pi和Ci分別是物品體積、價值和數量。(1 <= Wi, Pi <= 10000, 1 <= Ci <= 200)
輸出
輸出可以容納的最大價值。
輸入示例
3 6 2 2 5 3 3 8 1 4 1
輸出示例
9
請選取你熟悉的語言,並在下面的代碼框中完成你的程序,注意數據范圍,最終結果會造成Int32溢出,這樣會輸出錯誤的答案。
不同語言如何處理輸入輸出,請查看下面的語言說明。
【分析】我們把第i種物品看成單個的,一個一個的,我們想想二進制,任何一個數都可以由二的冪表示。
我們試試看,比如Ci = 14,我們可以把它化成如下4個物品:
重量是Wi,體積是Vi
重量是2 * Wi , 體積是2 * Vi
重量是4 * Wi , 體積是4 * Vi
重量是7 * Wi , 體積是7 * Vi
注意最后我們最后我們不能取,重量是8 * Wi , 體積是8 * Vi 因為那樣總的個數是1 + 2 + 4 + 8 = 15個了,我們不能多取對吧?
我們用這4個物品代替原來的14個物品,大家可以試試原來物品無論取多少個,重量和體積都可以靠我們這幾個物品湊出來,這說明我們這種分配方式和原來是等價的。
我們轉化為一般方法,對於Ci ,我們的拆分方法是:
1,2,4,8…… 同時Ci減去這些值,如果Ci不夠減了,則把最后剩余的算上,同時我們體積也對應乘以這些系數。這樣Ci個同一種物品,被我們變成了logCi個物品了。於是按照0-1背包的做法,時間復雜變為O(W * sigma(logCi))了,降了很多。
View Code
我們試試看,比如Ci = 14,我們可以把它化成如下4個物品:
重量是Wi,體積是Vi
重量是2 * Wi , 體積是2 * Vi
重量是4 * Wi , 體積是4 * Vi
重量是7 * Wi , 體積是7 * Vi
注意最后我們最后我們不能取,重量是8 * Wi , 體積是8 * Vi 因為那樣總的個數是1 + 2 + 4 + 8 = 15個了,我們不能多取對吧?
我們用這4個物品代替原來的14個物品,大家可以試試原來物品無論取多少個,重量和體積都可以靠我們這幾個物品湊出來,這說明我們這種分配方式和原來是等價的。
我們轉化為一般方法,對於Ci ,我們的拆分方法是:
1,2,4,8…… 同時Ci減去這些值,如果Ci不夠減了,則把最后剩余的算上,同時我們體積也對應乘以這些系數。這樣Ci個同一種物品,被我們變成了logCi個物品了。於是按照0-1背包的做法,時間復雜變為O(W * sigma(logCi))了,降了很多。
(關於此題還有復雜度更低的方法,留作大家思考)

#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <map> #include <queue> #include <stack> #include <vector> #include <list> #define inf 0x3f3f3f3f typedef long long ll; using namespace std ; ll n,m,a[50005],dp[50005]; ll b[505],w[20005],v[20005]; int main() { int W,V,C,cnt=0; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>W>>V>>C; for(int j=1;;j*=2) { if(C>=j){w[cnt]=j*W;v[cnt]=j*V;C-=j;cnt++;} else {w[cnt]=C*W;v[cnt]=C*V;cnt++;break;} } } for(int i=0;i<cnt;i++) { for(int j=m;j>=w[i];j--) { dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } } cout<<dp[m]<<endl; return 0 ; }