CompletePack - 完全背包模板

From《背包九讲》,稍作修改。


题目:

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路:

类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件..等很多种

01背包的状态转移方程f[v]=max{f[v],f[v-k*c[i]]+k*w[i]}(0<=k*c[i]<=v),总复杂度超过O(VN)。
优化后的状态转移方程f[v]=max{f[v],f[v-c[i]]+w[i]}

由01背包转换过来的解法延伸

  • 时间总复杂度较高,一般都会TLE。有个小小的地方优化,虽然大多数没有什么卵用:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。
  • 一个常用的优化:利用二进制的思想将一件物品拆成多件物品。把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k<=V。这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。
    • 中心思想:任何小于n的数都可以有{2^0,2^1,2^2,..2^k}该集合中的数加得
    • 例如1~13之间的任何一个数都可以用这些数加来,该集合为{ 2^0,2^1,2^2,2^3} ->{1,2,4,8},可以心算一下,从1-13这13个数都可以用这个集合里面的数相加得到,大大减少了枚举的数量。

最优化的代码模板:

for(int i=1;i<=n;i++)
{
    for(int j=c[i];j<=V;j++)
    {
        f[j] = max(f[j],f[j-c[i]] + w[i]);
    }
}

注意到第二个for是从c[i]枚举到V,目的是为了确保每件物品可取多件,从小的状态枚举到大的状态无非是保证该物品小状态里面可能取过。


模板到此为止,还需多做好题来练思维呐少年!
优哉游哉不是好ACMer!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值