背包问题
-
01背包
-
问题:给一个容量为V的背包,以及N个物品,每个物品的体积是ci,价值是wi,将那些物品放到背包中能使得价值之和最大,求这个最大值。
-
思路:设dp[i][v]为前 i种物品放到容量为v的背包中能得到的最大价值。
由于第i个物品要么放入背包要么不放入,所以状态转移方程为 dp[i][v]=max(dp[i-1][v],dp[i-1][v-ci]) -
复杂度:使用滚动数组优化空间复杂度为O(V),时间复杂度为O(N*V)
-
关键代码:
for(int i=1;i<=n;i++)
for(int j=c[i];j<=v;j++)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]+w[i]);
for(int i=1;i<=n;i++)
for(int j=v;j>=c[i];j--)
dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
-
完全背包
-
问题:和01背包的不同之处就是每件物品的个数是无限的
-
思路1:转换成01背包。
尽管每件物品的个数是无限的,但是背包的容量是有限的,所以每件物品其实最多只能放V/ci个。每件物品最终在背包中的数量都可以表示成2^k 的和(2进制表示),所以每件物品都可以被换成多个01背包中的物品,它们的体积和价值分别为(2^k )*ci和(2^k )*wi。每个物品都转换成log2(V/ci)件01背包中的物品,然后就可以使用01背包的方法解决问题了。 -
思路2:dp[i][v]还是表示前 i种物品放到容量为v的背包中能得到的最大价值。由于第i件物品可以不放也可以放多次,所以dp[i][v]可以由dp[i-1][v] (第i件物品没有放)和dp[i][v-ci]+wi (第i件物品至少放了多件,至少1件)转换来, 所以得到状态转换方程为 dp[i][v]=max(dp[i-1][v],dp[i][v-ci]+wi)。
-
思路2的关键代码:
思路2也可以使用滚动数组来优化空间复杂度,不使用滚动数组的代码就不帖了。
for(int i=1;i<=n;i++)
for(int j=c[i];j<=v;j++)
dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
思路2的时间复杂度比思路1的要小,处理一件物品的时间复杂度为O(V),总的时间复杂度为O(N*V)。二思路1处理一件物品的时间复杂度为O(V*log2(V/ci)),总的复杂度为O(N*V*∑log2(V/ci))
-
多重背包
-
问题: 和完全背包问题不同,多重背包中,每个物品的个数并不是无限的,最多mi件。
-
思路1:和完全背包一样可以将每件物品转换成多件01背包中的物品,然后使用01背包的方法来解决。(处理每件物品的时间复杂度为O( V*log2(mi) ) 。)
-
思路2:可以使用01背包和完全背包的混合来解决,当mi*c i< V 时,将这件物品转换成多个01背包中的物品再来处理;当mi*ci>=V时使用完全背包的方法来处理这件物品。(当mi*c i< V 时处理一件物品的时间复杂度为O( V*log2(mi) ),但是当mi*ci>=V时,处理一件物品的时间复杂度可以变为O(V),见前面完全背包)
-
思路2要比思路1的时间复杂度更小
这里只是粗略地写了一篇关于背包问题的博客,主要用于我个人学习,勿喷。
背包问题还有很多内容(前三种的组合、分组背包问题、具有依赖关系的背包问题、二维背包问题。。。。。。),感兴趣的可以自行去看背包九讲。