[Acwing]1019.庆功会 原创
算法标签 多重背包问题
题目简叙
处理这个问题之前,我们先了解一下多重背包问题

解析
你可以把它理解为01背包问题或者完全背包问题的变体
唯一的区别就是在两者基础上加入了一个东西能放多少个,所以我要加入一个循环
#include<iostream>
using namespace std;
const int N=1e2+10;
int f[N][N];
int v[N],w[N],s[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>v[i]>>w[i]>>s[i];//s 一个物品最多能获取多少个
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k*v[i]<=j&&k<=s[i];k++)//我们挑取K个第i个物品,且总重量不能大于s[i]
f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);//我们挑取K个第i个物品,可以挑选多少个
int res=1;
for(int i=0;i<=m;i++)res=max(res,f[n][i]);//在同样挑选完毕 但是重量不同的方案中得到最佳答案
cout<<res;
return 0;
}

优化
优化逻辑参照我前两题写的
Q:为什么这里的 注意点1 需要从大到小循环?
A:因为我们压缩的了代码,将二维降低到了一维,f[i, j] = max(f[i - 1, j], f[i - 1, j - v] + w,那么只能从大到小循环,否则计算j时,j - v会先被计算,那么其实算的就是f[i, j] = max(f[i - 1, j], f[i], j - v] + w了,不等价。
#include<iostream>
using namespace std;
const int N=1e2+10;
int f[N];
int main()
{
int n,m;
cin>>n>>m;
int v,w,s;
for(int i=1;i<=n;i++)
{
cin>>v>>w>>s;
for(int j=m;j>=0;j--)//注意点1
for(int k=0;k*v<=j&&k<=s;k++)
f[j]=max(f[j],f[j-k*v]+k*w);
}
cout<<f[m];
return 0;
}

现在我们来查看庆功会这道题

很明显是多重背包的裸题
我们直接利用上面优化出来的方式解决这道题目
#include<iostream>
using namespace std;
const int N = 6e3+10;
int f[N];
int main()
{
int n,m;
cin>>n>>m;
int v,w,s;
for(int i=0;i<n;i++)
{
cin>>v>>w>>s;
for(int j=m;j>=0;j--)
for(int k=0;k*v<=j&&k<=s;k++)
f[j]=max(f[j],f[j-k*v]+k*w);
}
cout<<f[m];
return 0;
}


浙公网安备 33010602011771号