传送门:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1086
题目描述:有N种物品,每种物品的数量为C1,C2......Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数)。求背包能够容纳的最大价值。
分析:本题是多重背包问题,我们显然可以把每种物品的每一件都作为一个新的物品按照普通0-1背包的方法做。
但是0-1背包的时间复杂度是O(W * N) , 这里N = C1 + C2 + …+ Cn。
如果用dp[i][j]表示前i件物品,总重量为j的时候的最大价值。那么dp[i][j] = max{dp[i – 1][j – k * Wi] + k * Vi},其中 0 ≤ k ≤ min( j / Wi , Ci),这个的时间复杂度是n * W * max(Ci)。
其实我们还是应该将问题转化为0-1背包的方法解决,利用二进制的方法。每个数都可以拆分为2的次方,这样通过将数量进行2的次方拆分,得到新的重量和价值的物品。如:
数量为11的物品可拆分为1+2+4+4=11。
这样就拆分为了四个物品:重量为w,价值v;重量2*w,价值2*v...之后就可以用0-1背包的方法解决了。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[50005];
int w[1005],v[1005];
int main()
{
int N,W;
scanf("%d%d",&N,&W);
int sum=0;
int x,y,z;
for(int i=1;i<=N;i++)
{
scanf("%d%d%d",&z,&y,&x);
int tmp=1;
while(x>0)
{
if(x>=tmp)
{
w[++sum]=tmp*z;
v[sum]=tmp*y;
x=x-tmp;
}
else
{
w[++sum]=x*z;
v[sum]=y*x;
x=0;
}
tmp=tmp*2;
}
}
for(int i=0;i<=W;i++)
dp[i]=0;
for(int i=1;i<=sum;i++)
{
for(int j=W;j>=0;j--)
{
if(j>=w[i]) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[W]<<endl;
return 0;
}