多重背包是指装入背包的若干见物品种,可以拿的数量有上限。
第一种就是二进制优化,转换成01背包,例如一件物品可以拿26件,每一件的权值是w,26可以写成(1+2+4+8)+11,所以就把这种物品分解成权重为w,2w,4w,8w,11w的五种物品,这五种物品组合,一定能组成小于等于26的任意一个数,这样就把有26件的一种物品换成了五种各有一件的物品,用01背包就能解决了。
poj1276的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<climits>
#include<list>
#include<stack>
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
int dp[100002];
int w[200];
int main()
{
int ans_v;
while(scanf("%d",&ans_v)!=EOF)
{
int t=0;
int n;
scanf("%d",&n);
int i;
for(i=0;i<n;++i)
{
int mi,wi;
scanf("%d%d",&mi,&wi);
int base=1;
int sum=1;
while(sum<=mi)
{
w[t]=wi*base;
base*=2;
sum+=base;
t++;
}
if(sum-base<mi)
{
w[t++]=(mi-(sum-base))*wi;
}
}
mem(dp);
for(i=0;i<t;++i)
{
for(int j=ans_v;j>=w[i];--j)
{
dp[j]=max(dp[j],dp[j-w[i]]+w[i]);
}
}
printf("%d\n",dp[ans_v]);
}
}
而另一种方法是维护一个数组num,num[i][j]表示在往背包里试着装第i件物品时,背包容量使用了j时装了多少件i物品。cost[i]为物品i的体积,num[i][j]=num[j-cost[i]]+1;可以看到num[i][j]和num[t|t!=i][j|j=1,2,....v]没有任何关系,所以可以省掉第一维,对于每一种物品,清空num,只计算num[j]就行了。
同样是poj1276的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<climits>
#include<list>
#include<stack>
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
int wi[20];
int mi[20];
int dp[100050];
int num[100050];
int main()
{
int ans_v;
while(scanf("%d",&ans_v)!=EOF)
{
int n;
mem(dp);
mem(num);
scanf("%d",&n);
int i;
for(i=0;i<n;++i)
{
scanf("%d%d",&mi[i],&wi[i]);
}
for(i=0;i<n;++i)
{
int j;
mem(num);
for(j=wi[i];j<=ans_v;++j)
{
if(dp[j-wi[i]]+wi[i]>dp[j]&&num[j-wi[i]]<mi[i])
{
dp[j]=dp[j-wi[i]]+wi[i];
num[j]=num[j-wi[i]]+1;
}
}
}
printf("%d\n",dp[ans_v]);
}
}