一、01背包
01背包是在N件物品取出若干件放在空间为M的背包里,使得所装物品价值最大。每件物品的体积为W[1],W[2] ~ W[N],与之相对应的价值为V[1],V[2] ~ V[N]。同时还需要M个背包F[1],f[2]~f[M],空间依次为1,2 ~ M,其值表示相应空间的背包当前所装物品的最大价值。(后面会解释为何需要M个背包)
01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个(或者最多只能选取一个),并且有权值和体积两个属性。
在01背包问题中,因为每种物品只有一个(或者最多只能选取一个),对于第i个物品只需要考虑选与不选两种情况。那么选与不选的依据是什么呢?当然是该物品的性价比咯,而不是看当前背包所剩空间还能否装得下该物品。因为背包的剩余空间是不断根据选择的物品而变化的。
那么怎么判断选不选这个物品呢,就是看选了这个物品和不选这个物品背包的价值哪个大。就是max(不选的价值,选的价值)。不选:背包的价值就不变,选:背包的价值就等于这个物品的价值加上装了这个物品之后背包剩余空间用来装前(i-1)个物品的最大价值。那么剩余空间能装的最大价值是多少呢,是不是就相当于容量为剩余空间的背包能装的最大价值,而那我们是不是就应该知道所有容量为可能剩余空间(0~M-1)的背包所能装的最大价值呢,这就是为什么我们需要M个背包。同时也意味着我们需要同时计算这M个背包能装的最大价值,只不过最后只需要输出容量为M的背包能装的最大价值。
我想到这儿问题的解决方法应该就比较清晰了,下面直接看代码
二、核心代码
for(i=1;i<=N;i++){
for(j=M;j>=W[i];j--) //对于每个容量比该物品大的背包都要判断
F[j]=max(F[j],F[j-W[i]]+V[i]);
}
printf("%d",F[M]);
注意!!!第二层for循环要从M—>W[i],因为当j从高到低时,F[j-W[i]]表示的才是容量为j-W[i]的背包用来装前i-1个物品的最大价值。如果从低到高的话会导致计算后面的背包时,前面的背包可能已经装入了第i个物品。
三、完全背包
完全背包与01背包的区别就是完全背包的物品的数量无限并且可以重复选择。那么就意味着第i种物品可以选取0~M%W[i]个,也就是说当选择第i种物品时,容量为j-W[i]的背包里可能已经装有该种物品了。那么第二层循环的顺序就不能是从高到低了,而得是从低到高。
四、核心代码
for(i=1;i<=n;i++)
//for(j=m;j>=w[i];j--) //01背包
for(j=w[i];j<=m;j++) //完全背包
f[j]=max(f[j],f[j-w[i]]+v[i]);
printf("%d",f[m]);