背包问题
背包问题多变灵活,下面介绍两种常见的背包问题:01背包和完全背包问题。在正式开始解释之前,我要引入一个非常重要的概念:多阶段动态规划问题。
多阶段动态规划问题
动态规划问题通常都具有时间或空间上的次序性,因此求解这类问题时,首先要将问题按一定的次序划分成若干相互联系的阶段。
01背包
所谓01背包就是指☞,一件物体因为只有一件,所以只有两种状态:取或不取。
例题
给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi ,每个物品只有一件。
测试样例
5 8 n c
3 5 1 2 2 w[]
4 5 2 1 3 V[]
输出样例
10
解题思路
解释,设二维数组dp[i][v]表示用前i件物品装入质量为v时的最大价值,而dp[0][v]就为0;
因此可以得到状态转移方程
//选第i件,从背包中去除w[i]空间,
dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+V[i]);
//不选第i件,
==========
动态
for(int i=1;i<=n;i++){
for(int j=w[i];j<=m;j++){
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
}
}
由此可以得到01背包的示意图:
空间优化
我们不难看出,对于dp[i][v],它的值只与dp[i-1]的两个数据有关,而到i+1时,dp[i-1]又没有用了,所以可以直接开个一维数组dp[i],表示装重量为i的元素的最大值;
于是可得如下代码:
for(int i=1;i<=n;i++){
for(int j=v;j>=w[i];j--){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
}
}
需要注意的是: 重量的遍历必须要保证逆序,因为如果是正序的话,在遍历dp[v]时,dp[v-w[i]]是已经用w[i]更新过的值,也就意味着第i个物品的数量不唯一,与题目矛盾。
完全背包
完全背包问题与01背包问题的最大区别就是01背包中的每个物品数量有且只有1个,而完全背包中每个物品可以有无限个;
解题思路
根据上面01背包问题的分析,可以得到如下的状态转移方程
dp[i][v]=max(dp[i-1][v],dp[i][v-w[i]]+c[i])
与01背包的区别就在于,转移的状态是dp[i][v-w[i]],因为完全背包中每个物品的数量是无限的,可以多次放第i件物品;
空间优化
for(int i=1;i<=n;i++){
for(int j=w[i];j<=v;j++){
dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
}
}
/*
因为第i件物品的数量不唯一,所以应正序遍历;
*/
例题
完全背包的变型:
https://blog.csdn.net/alpha_xia/article/details/115555699
01背包问题:
https://blog.csdn.net/alpha_xia/article/details/115598319