一般的思路:
把多重背包转化为01背包,但这样时间复杂度是不变的,依然会TLE。
二进制优化:
把第 i 种物品的 num【i】 分为 数个新的物品:
分配为:
1,2,4.....2^c (2^c < num[ i ])
剩下的数量都可以由这些二进制组合而成。
CODE(以51NOD1086为例):
#include <cstdio>
int n,m,dp[50010],weight[10010],value[10010],num[220];
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;++i)
scanf("%d%d%d",&weight[i],&value[i],&num[i]);
for(int i=1;i<=m;++i)
dp[i]=0;
for(int i=1;i<=n;++i)
{
if(weight[i]*num[i]>=m)
{
for(int j=weight[i];j<=m;++j)
dp[j]=(dp[j]>(dp[j-weight[i]]+value[i]))?dp[j]:dp[j-weight[i]]+value[i];
}
else
{
int tmpnum=num[i],tmpweight,tmpvalue,xishu=1;
while(xishu<=tmpnum)
{
tmpvalue=value[i]*xishu;
tmpweight=xishu*weight[i];
for(int j=m;j>=tmpweight;--j)
dp[j]=(dp[j]>(dp[j-tmpweight]+tmpvalue))?dp[j]:dp[j-tmpweight]+tmpvalue;
tmpnum-=xishu;
xishu<<=1;
}
if(tmpnum)
{
tmpvalue=tmpnum*value[i];
tmpweight=tmpnum*weight[i];
for(int j=m;j>=tmpweight;--j)
dp[j]=(dp[j]>(dp[j-tmpweight]+tmpvalue))?dp[j]:dp[j-tmpweight]+tmpvalue;
}
}
}
printf("%d\n",dp[m]);
}
}
/*
3 6
2 2 5
3 3 8
1 4 1
*/
解释:
1.分类讨论:
第一种情况: //不太理解这一部分
第二种情况: 二进制拆分+01背包,这个简单
没了。。。ORZ