1086 背包问题 V2-多重背包-深度理解

  •  
  • 1086 背包问题 V2

  • 先来一发无任何优化的:
  •       for (int i=1; i<=n; i++)
  •                 f[i][0]=0;
  •             for (int j=w[i]; j<=v; j++)
  •                    int count=min(num[i],j/w[i]);
  •                 for (int k=0; k<=count; k++)
  •                         f[i][j]=max(f[i][j],f[i-1][j-k*w[i]]+k*c[i])
  • 容易发现的是f[i][j−k∗c[i]]f[i][j−k∗c[i]]会被f[i][j−(k+1)∗c[i]]f[i][j−(k+1)∗c[i]]影响 (很明显吧
  • (我们通过一件体积为c[i]c[i]的物品填充体积为j−(k+1)∗c[i]j−(k+1)∗c[i]的背包,会得到体积为j−k∗c[i]j−k∗c[i]的背包.)
  • 所以我们可以根据对c[i]c[i]取模得到的余数进行分组.
  • 即可分为0,1,2,3…c[i]−10,1,2,3…c[i]−1 共c[i]c[i]组
  • 每组之间的状态转移不互相影响.
  • 这里一些推导过程我会写的尽量详细(我也知道看不懂有多难受. qwq
  • 令d=c[i],a=j/c[i],b=j%c[i]
  • 其中a为全选状况下的物品个数.
  • 则j=a∗d+bj=a∗d+b
  • 则带入原始的状态转移方程中
  • j−k∗d=a∗d+b−k∗dj−k∗d=a∗d+b−k∗d =(a−k)∗d+b=(a−k)∗d+b
  • 我们令(a−k)=k′(a−k)=k′
  • 再回想我们最原始的状态转移方程中第二状态 : f[i][j−k∗c[i]]+k∗w[i]f[i][j−k∗c[i]]+k∗w[i] 代表选择kk个当前ii物品.
  • 根据单步容斥 :全选−−不选=选.
  • 因此 a−(a−k)=ka−(a−k)=k
  • 而前面我们已经令(a−k)=k′(a−k)=k′
  • 而我们要求的状态也就变成了
  • f[i][j]=max(f[i−1][k′∗d+b]+a∗w[i]−k′∗w[i])f[i][j]=max(f[i−1][k′∗d+b]+a∗w[i]−k′∗w[i])
  • 而其中,我们的a∗w[i]a∗w[i]为一个常量(因为a已知.)
  • 所以我们的要求的状态就变成了
  • f[i][j]=max(f[i−1][k′∗d+b]−k′∗w[i])+a∗w[i]f[i][j]=max(f[i−1][k′∗d+b]−k′∗w[i])+a∗w[i]
  • 根据我们的
  • k∈[1,lim]k∈[1,lim]
  • 容易推知
  • k′∈[a−k,a]k′∈[a−k,a]
  • 那么
  • 当前的f[i][j]f[i][j]求解的就是为lim+1lim+1个数对应的f[i−1][k′∗d+b]−k′∗w[i]f[i−1][k′∗d+b]−k′∗w[i]的最大值.
  • (之所以为lim+1lim+1个数,是包括当前这个jj,还有前面的物品数量.)
  • 将f[i][j]f[i][j]前面所有的f[i−1][k′∗d+b]−k′∗w[i]f[i−1][k′∗d+b]−k′∗w[i]放入一个队列.
  • 那我们的问题就是求这个最长为lim+1lim+1的队列的最大值+a∗w[i]a∗w[i].
  • 因此我们考虑到了单调队列优化
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值