多重背包问题
- 多重背包问题,就是在背包问题的大逻辑前提之下,每一件物品它都有个数的限制,多重背包问题需要进行二进制优化并最终通过01背包问题思路来解决
- 既然多重背包问题当中每一件物品都有自己的个数的限制,比如说有物品i有k个,那就把这k个相同物品给他分成一组一组,每组的数量分别是1,2,4,8,16…(2的整次幂),并且总的数量不能够超过k。举个例子,比方说有11个,那么就分成如下几组:1,2,4,4(是11-1-2-4),因为这些被分出来的组最终是要充当01背包问题当中的每个物品,为了保持题意的不变性,假设在01背包问题把这些物品全部拿的话,最后该物品i的总数应该保持为k.(为什么要这样呢?一个数能够被拆分为任意二进制的和。 (这个原理造出来好多算法啊QAQ)
T=2^ p1 +2^ p2+2^ p3+…+2^pn)
- 所以说在每个物品的权重,体积以及个数在输入的时候,就可以对他进行二进制优化分组,把这么多个数的同一个物品给他分成若干组,然后放到v,w中,每一组最后需要充当01背包问题的一个物品
int cnt=1;
for (int i=0;i<n;i++)
{
scanf("%d %d %d",&a,&b,&s);
int num=1;
while(num<=s)
{
v[cnt]=a*num;
w[cnt]=b*num;
cnt++;
s-=num;
num*=2;
}
if (s>0)
{
v[cnt]=s*a;
w[cnt]=s*b;
cnt++;
}
}
- 接下来就是01背包问题的事情了
n=cnt-1;
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]);
}
}
printf("%d\n",f[m]);
例题
来源:AcWing
luck
#include <stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define N 12000
int n,m,a,b,s;
int v[N];
int w[N];
int f[N];
int main()
{
scanf("%d %d",&n,&m);
int cnt=1;
for (int i=0;i<n;i++)
{
scanf("%d %d %d",&a,&b,&s);
int num=1;
while(num<=s)
{
v[cnt]=a*num;
w[cnt]=b*num;
cnt++;
s-=num;
num*=2;
}
if (s>0)
{
v[cnt]=s*a;
w[cnt]=s*b;
cnt++;
}
}
n=cnt-1;
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]);
}
}
printf("%d\n",f[m]);
return 0;
}