-
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].
- 因此我们考虑到了单调队列优化
1086 背包问题 V2-多重背包-深度理解
最新推荐文章于 2019-10-15 19:29:22 发布