版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sunshiness_s/article/details/82590105
多重背包裸题…
表示物品个数, 表示物品体积, 表示物品价格,以下不做特殊解释
多重背包的问题,我们可以物品拆开,然后用01背包来求,复杂度是
但显然这样复杂度比较大,有两种优化:二进制分组、单调队列优化
先来说下二进制分组,也是把物品拆开,只不过不是拆成一个,而是根据二进制拆,因为我们知道1、2、4、8…可以组成所有数。因此把一个物品拆成log份,复杂度为
而单调队列优化可以优化到
考虑转移方程
其中
设
,即
转移方程变为
其中
再令
,得到
其中
因此枚举
,用单调队列维护
最大值即可
#include <cstdio>
#include <algorithm>
using namespace std;
#define N 10010
#define mp make_pair
pair<int,int>q[N];
int n,m,w[N],v[N],c[N],f[N*5];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d%d%d",&w[i],&v[i],&c[i]);
for(int i=1;i<=n;i++){
c[i]=min(c[i],m/w[i]);
for(int d=0;d<w[i];d++){ //枚举余数
int st=1,ed=0;
for(int j=0;j<=(m-d)/w[i];j++){
int tmp=f[j*w[i]+d]-v[i]*j;
while(st<=ed && tmp>=q[ed].first) ed--;
while(st<=ed && q[st].second<j-min(c[i],j)) st++;
q[++ed]=mp(tmp,j);
f[j*w[i]+d]=q[st].first+j*v[i];
}
}
}
printf("%d\n",f[m]);
return 0;
}