问题描述
有N种物品和一个容量为V的背包,第i中物品最多有n[i]件可用。每一件的费用是c[i],价值是w[i]。
求将哪些物品放入背包可以使得这些物品的费用总和不超过背包的容量,同时价值总和最大。
问题分析
这个问题的状态转移方程和完全背包的十分的相似,唯一改变的就是第i种物品只有1+n[i]种策略可选择。
分别是0,1,2,....n[i]。
dp[i,v]=max{ dp[i-1,v],dp[i-1,v-k*c[i]]+k*w[i] }
这《背包九讲》中将这个问题转换。基本思想就是将第i种分成若干份,使得第i中物品可取的
每一种策略即取0,1,2,3.....n[i] 都可以等价的取若干份来代替。
于是现在的问题便是第i中物品应该怎样的份才能达到上述的目的呢??
定理:一个正整数n可以被分解成1,2,4,....,2k-1 n-2k-1+1 (其中k是满足n-2k-1+1>0的最大整数)的形式,
且1~n内的所有整数都可以唯一表示成1,2,4,....,2k-1 n-2k-1+1中某几个数的和的形式。
因此按照这个定理,我们把第i中物品的个数n[i]分成1,2,4,....,2k-1 n-2k-1+1的形式。
也就是把第i种物品细分了,每一分的个数为1,2,4,....,2k-1 n-2k-1+1。 于是我们将问题边转换了这些细分后物品的01背包问题。
于是这个代码可以表示为:
produce MultiplePack(int cost, int weight,int amount)
if cost*amout>=V
CompletePack(cost,weight) //这一份物品不能全部放入取了以后有剩余,那么对于背包这个物品有无限个
return
int k=1
while(k<=amount)
ZeroOnePack(k*cost,k*weight)
amount-=k
k*=2
ZeroOnePack(amount*cost,amount*weight)
if cost*amout>=V
CompletePack(cost,weight) //这一份物品不能全部放入取了以后有剩余,那么对于背包这个物品有无限个
return
int k=1
while(k<=amount)
ZeroOnePack(k*cost,k*weight)
amount-=k
k*=2
ZeroOnePack(amount*cost,amount*weight)
这里需要01背包和完全背包作为基础。