引入
一般的背包问题是这样的:给出个物品,每个物品价值,体积,求容量为的背包能容纳的最大价值。
多重背包则给出了种物品,每种物品除了上述属性外,还有一个属性代表物品数量,仍然求容量为的背包能容纳的最大价值。
做法
朴素的方法是把每种物品拆分成件物品,转化为一般的背包问题,时间复杂度为。
另一种方法,则是利用二进制的性质;我们知道二进制的第位数可以表示为,故是可以把内所有的数表示出来的。
所以,把拆成即可把所有数表示出来,(注意这里的不是严格的,而是向下取整后的结果),即把每种物品分成若干份,每份看成一件物品,但容量和价值都为原来的倍,时间复杂度为。
例题
http://www.51nod.com/contest/Problem.html#!problemId=1086&contestId=55
其实就是一道模板题,直接上代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct newdata
{
int value,v;
};
int n,w,cnt;
newdata a[20001];
int dp[50001];
int main()
{
scanf("%d%d",&n,&w);
for (int i=1;i<=n;i++)
{
int c,v,p;
scanf("%d%d%d",&v,&p,&c);
int len=int(log2(c));
for (int j=0;j<=len;j++)
if (c>=1<<j)
{
a[++cnt].v=(1<<j)*v;
a[cnt].value=(1<<j)*p;
c-=1<<j;
}
else
{
a[++cnt].v=c*v;
a[cnt].value=c*p;
break;
}
}
for (int i=1;i<=cnt;i++)
for (int j=w;j>=a[i].v;j--)
dp[j]=max(dp[j],dp[j-a[i].v]+a[i].value);
int ans=0;
for (int i=0;i<=w;i++)
ans=max(ans,dp[i]);
printf("%d",ans);
}