Loading... <div class="tip inlineBlock info"> 完全背包是枚举第`i`个物品选几个,分组背包是枚举第`i`组物品选那个。 </div> **理解分组背包:** - N组:水果、蔬菜 - 水果:葡萄、香蕉、苹果 - 蔬菜:萝卜、白菜 # 分组背包问题 有 N 组物品和一个容量是 V 的背包。 每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。 求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。 输出最大价值。 #### 输入格式 第一行有两个整数 `N`,`V`,用空格隔开,分别表示物品组数和背包容量。 接下来有 `N` 组数据: * 每组数据第一行有一个整数 `Si`,表示第 `i` 个物品组的物品数量; * 每组数据接下来有 `Si` 行,每行有两个整数 `vij`,`wij`,用空格隔开,分别表示第 `i`个物品组的第`j` 个物品的体积和价值; #### 输出格式 输出一个整数,表示最大价值。 #### 数据范围 `0<N,V≤100` `0<Si≤100 ` `0<vij,wij≤100` #### 输入样例 ``` 3 5 2 1 2 2 4 1 3 4 1 4 5 ``` #### 输出样例: ``` 8 ``` ## 基本思考框架 ![](https://blog.fivk.cn/usr/uploads/2022/01/2692750078.png) ```cpp include<bits/stdc++.h> using namespace std; const int N=110; int f[N][N]; //只从前i组物品中选,当前体积小于等于j的最大值 int v[N][N],w[N][N],s[N]; //v为体积,w为价值,s代表第i组物品的个数 int n,m,k; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>s[i]; for(int j=0;j<s[i];j++){ cin>>v[i][j]>>w[i][j]; //读入 } } for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++){ f[i][j]=f[i-1][j]; //不选 for(int k=0;k<s[i];k++){ if(j>=v[i][k]) f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]); } } } cout<<f[n][m]<<endl; } ``` 因为只用到了第i-1列,所以可以仿照01背包的套路逆向枚举体积 ```cpp #include<bits/stdc++.h> using namespace std; const int N=110; int f[N]; int v[N][N],w[N][N],s[N]; int n,m,k; int main(){ cin>>n>>m; for(int i=0;i<n;i++){ cin>>s[i]; for(int j=0;j<s[i];j++){ cin>>v[i][j]>>w[i][j]; } } for(int i=0;i<n;i++){ for(int j=m;j>=0;j--){ for(int k=0;k<s[i];k++){ //for(int k=s[i];k>=1;k--)也可以 if(j>=v[i][k]) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]); } } } cout<<f[m]<<endl; } ``` 最后修改:2022 年 01 月 07 日 © 禁止转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏