多重背包问题
学过01背包和完全背包后,多重背包就很好理解了。
01背包物品个数只有一个,完全背包个数有无限个,多重背包个数为给定的数目。
题目:
输入的第一行为测试样例的个数T,接下来有T个测试样例。
每个测试样例的第一行是物品种数N(1 ≤ N ≤ 100)和背包容量C(C ≤ 10000)。
接下来N行,每行三个正整数,Wi ,Vi 和 Mi ( Wi ≤ 10000, Vi ≤ 10000, Mi ≤ 1000 ),分别表示第i种物品的重量 Wi ,价值 Vi ,及个数 Mi 。
代码参考:https://blog.csdn.net/tinyguyyy/article/details/51203935
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=10006; 5 const ll inf=0x3f3f3f3f; 6 7 int n,W; ///n为物品种类,W为背包重量 8 int w[maxn],v[maxn],M[maxn],dp[maxn]; ///w为重量,v为价值,M为个数 9 10 void complete(int x) ///完全背包 11 { 12 for(int i=w[x];i<=W;i++) 13 dp[i]=max( dp[i], dp[i-w[x]]+v[x]); 14 } 15 16 void zero_one(int cost,int weight) ///01背包 17 { 18 for(int i=W;i>=weight;i--) 19 dp[i]=max(dp[i],dp[i-weight]+cost); 20 } 21 22 void solve() 23 { 24 for(int i=0;i<n;i++){ 25 if(w[i]*M[i]>W) complete(i); ///此处用完全背包,因为物品个数能放各个位置 26 else{ 27 int mid=1; 28 ///取得光的话,去遍历每种取法 29 ///这里用到是二进制思想,降低了复杂度 30 ///为什么呢,因为他取的1,2,4,8...与余数个该物品,打包成一个大型的该物品 31 ///这样足够凑出了从0-k个该物品取法 32 ///把复杂度从k变成了logk 33 ///如k=11,则有1,2,4,4,足够凑出0-11个该物品的取法 34 while( mid<M[i]){ 35 zero_one(mid*v[i],mid*w[i]); 36 M[i]-=mid; 37 mid<<=1; 38 } 39 zero_one(M[i]*v[i],M[i]*w[i]); 40 } 41 } 42 } 43 44 int main() 45 { 46 ios::sync_with_stdio(0); std::cin.tie(0); 47 int T; 48 while(cin >> T){ 49 while(T--){ 50 cin >> n >> W; 51 memset( dp, 0, sizeof dp); 52 53 for(int i=0;i<n;i++) 54 cin >> w[i] >> v[i] >> M[i]; 55 56 solve(); 57 58 cout << dp[W] << endl; 59 } 60 } 61 62 return 0; 63 }