多重背包问题

  学过01背包和完全背包后,多重背包就很好理解了。

  01背包物品个数只有一个,完全背包个数有无限个,多重背包个数为给定的数目。

  题目:

  输入的第一行为测试样例的个数T,接下来有T个测试样例。

  每个测试样例的第一行是物品种数N(1 ≤ N ≤ 100)和背包容量CC ≤ 10000)。

  接下来N行,每行三个正整数,Wi ,Vi 和 M( 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 }
原文地址:https://www.cnblogs.com/ZQUACM-875180305/p/9034798.html