题目:
有N种物品和一个容量为V的背包,每种物品都有无限件可用。放入第i种物品的费用是Ci,价值是Wi,求解:将哪些物品装入背包,可使这些物品耗费的费用和不超过背包容量,且价值总和最大。
分析:
(一)建立状态方程
可以转化为01背包问题求解
dp[i][v]表示前i件种物品放入容量为v的背包的最大价值,则有:
dp[i][v]=max{dp[i-1][v-k*C[i]]+k*W[i]},其中0<=k*C[i]<=v,状态方程的建立不难理解
(二)根据状态方程实现代码
有了状态方程,看出i与i-1有关,所以i从1到N遍历,v与v-k*C[i]有关,所以k从0到k*C[i]<=v遍历
|
(三)优化数据结构
注意到状态方程中i只与i-1有关,可以消去一维,但是如果直接由上面的代码消维是不成的,因为我们用到了上一状态的V-k*C[i],也就是我们在进入下一状态前,这一状态的每一个dp[v],0<=v<=V,必须都是已知的,但是以上代码是对k进行遍历,和v无关,所以要对v进行遍历,那该如何写呢?
从状态方程中找线索,dp[i][v]=max{dp[i-1][v-k*C[i]]+k*W[i]},0<=k*C[i]<=V
我们再把它展开一下看,dp[i][v]=max{dp[i-1][v],dp[i-1][v-C[i]]+W[i],dp[i-1][v-2C[i]]+2W[i]……}
再来看我们需要的v,这个v范围是0<=v<=V,将v的范围带入上式看,我们发现虽然v-C[i],v-2C[i]看起来很繁琐,但是追根究底范围也一定是在0到V之间,
再来看它们之间的关系,发现后一个元素永远比前一个元素多了一个W[i],如果我们事先将dp[v-C[i]]+W[i]的值得到,那么当v增加一个C[i]时,取dp[v-C[i]],这里dp[v-C[i]]就是dp[v-C[i]]+W[i],然后再加上一个W[i],即dp[v-C[i]]+W[i]不就是取得两件i物品所获得的价值了吗!想到这,代码就可以实现了:
|
发现了吗?代码和01背包问题就内层循环的顺序不同而已,但是实际意义可是大不相同啊
(四)深入优化
如果再继续优化也是可以的,如果有两件物品i和j,有C[i]>C[j],W[i]<W[j],也就是i物品所占容量大于j物品,但是i物品的价值却低于j物品,那么i物品就可以不用考虑了