多重背包

朴素解法
每个物品数量只有固定数量个,只从前i个物品中选,并且总体积不超过j的选法
解法跟完全背包差不多,只不过我们k的范围是有限制的,其解法就跟完全背包差不多
#include<iostream>
#include<algorithm>
using namespace std;
const int N =110;
int s[N],v[N],w[N];
int n,m;
int f[N][N];
int main(){
cin >> n >> m;
for(int i=1; i<=n; i++){
cin >> v[i] >> w[i] >> s[i];
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
for(int k=0; k<=s[i] && k*v[i] <= j; k++){
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]*k]+w[i]*k);
}
}
}
cout<<f[n][m];
return 0;
}
二进制优化
-
在上述枚举物品数量的时候,我们需要从0一直枚举到其最大数量
如果物品数量有很多的话,我们这样的效率就会很低如果物品有1023个,我们不需要枚举到1023个
我们采用一种打包的方式
如 1 2 4 8…512 这几种"包裹"
选择1,2可以凑出来0~3数量,再选一个4就能凑出来0~7数量,
以此类推->我们选择1 2 4 8 16 32 64 128 256 512 就能凑出来1023这种数量每一个选择可以选0次或者1次,那么可以看作一个01背包问题
我们只需要计算每一个包裹的重量和价值即可
- 如何打包呢,如果物品数量有S个
我们枚举2的0,1,2,3…k次方直至2的k次方大于物品剩余数量
举例 物品 数量1000个
那么我们只需要分成 1 2 4 8 16 32 64 128 256 489 这几种包裹
- 如何打包呢,如果物品数量有S个
#include<iostream>
#include<algorithm>
using namespace std;
const int N =25000,M=2010;
int n,m;
int v[N],w[N];
int f[N];
int main(){
cin >> n >> m;
int cnt=0;//记录分成了几组
for(int i=1; i<=n; i++){
int a,b,s;
//体积 价值 数量
cin >> a >> b >> s;
//记录当前是2的几次方
int k=1;
while(k<=s){
cnt++;
v[cnt]=a*k;//这一组的重量
w[cnt]=b*k;//这一组的价值
s-=k;//在总数里减去这组的数量
k*=2;
}
if(s>0){
cnt++;
v[cnt]=a*s;
w[cnt]=b*s;
}
}
//最后没分完的话别忘了再单开一组
n = cnt;
//最后就是要在n组里选择
for(int i=1; i<=n; i++){
for(int j=m; j>=v[i]; j--){
f[j]=max(f[j],f[j-v[i]]+w[i]);
}
}
cout << f[m] << endl;
return 0;
}
分组背包

物品会分组,每一组里面只能选一个物品,如水果组选了苹果不能选香蕉
我们分组背包需要的是枚举第i组物品选哪个或者不选
#include<iostream>
#include<algorithm>
using namespace std;
const int N =110;
int v[N][N],w[N][N],s[N];
int n,m;
int f[N];
int main(){
//物品组数,背包容量
cin >> n >> m;
//n组数据,Si表示第i个物品组的物品数量
for(int i=1; i<=n; i++){
//第i个物品组的物品数量
cin >> s[i];
//第i个物品组的第j个物品的重量和价值
for(int j=1; j<=s[i]; j++){
cin >> v[i][j] >> w[i][j];
}
}
//枚举n个物品组
for(int i=1; i<=n; i++){
//这里是01背包的一维解法,需要倒序遍历背包容量
for(int j=m; j>=0; j--){
//第i组第k个物品的重量和价值
for(int k=1; k<=s[i]; k++){
//如果背包能装得下
if(v[i][k] <= j)f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
}
}
}
cout << f[m] << endl;
return 0;
}
结语
🌻编写本篇文章目的是笔者想以输出的形式进行学习,顺便记录学习点滴🌻
🌹 如果本篇文章对你有帮助的话那就点个赞吧👍🌹
😇 本篇文章存在多处不足,如有修改意见,可以私信或者评论哦,还望海涵 😇
文章内容部分参考于Acwing
1万+

被折叠的 条评论
为什么被折叠?



