给定n种物品和一个背包,物品i的重量是wi,其价值为 v i,背包的容量为C。
背包问题是如何选择装入背包的物品,使得装入背包中物品的总价值最大? 如果在选择 装入背包的物品时,对每种物品i只有两种选择:装入背包或不装入背包,即不能将物品i装入背包多次,也不能只装入物品i的一部分,则称为0/1背包问题
在0/1背包问题中首先需要考虑的限制条件就是:如果当前的第 i 个物品的重量大于了背包的剩余容量,那么就不能装入。
如果能装入,那我们再考虑到底要不要装入?也就是从 “装入” 和 “不装入”两个方面来获得背包的最大价值。
因此定义dp数组:dp [ i ] [ j ]
表示当背包的容量为 j 的时候,装入前 i 个物品可以获得的最大价值。
上述对 i 的解释是错误的,如果能装入前 i 个,那么总价值已经确定了,就没必要算了。
所以正确的解释是:
表示当背包的容量为 j 的时候,对于前 i 个物品,可以获得的最大价值。也就是可装可不装。
即获得我们本次算出的最优解,不仅是得出结果。
我们用一个一维数组 isLoad[ i ] 来表示物品 i 有没有被装入。值为1表示装入,为0表示未装入。
为了确定装入背包的具体物品,我们从 dp[ n ] [ w ] 往前推。如果dp[ n ] [ w ] > dp [ n - 1] [ w ],则说明第n个物品肯定被装入了背包,因为此时背包的价值更大。否则物品n肯定没有被放入背包。一个if-else就可以解决问题。
注意点在下面代码中,weight和value数组的下标是从1开始的,对应第 i 个物品。0下标没有用,数值用0代替。
代码#include#include using namespace std; int knapSack(int n, int w, int weight[], int value[], int isLoad[]) { // 多开辟的一个空间是为了容量为0和不装东西的情况 int dp[n+1][w+1]; // 定义dp数组 表示当容量为w的时候,对于前i个物品可以获得的最大价值 for(int i = 0 ; i <= n; i++) dp[i][0] = 0; // 容量为0 for(int i = 0 ; i <= w ; i++) dp[0][i] = 0; // 不装东西 // 动态规划 for(int i = 1 ; i <= n; i++) { for(int j = 1 ; j <= w ; j++) { // 准备放第i个物品 if(j < weight[i]) { // 背包的剩余容量不够了 就不放 dp[i][j] = dp[i-1][j]; // 不装 } else { dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]); } } } // 获得装入背包的物品 存放在isLoad数组中 int j = w; for(int i = n ; i >= 1 ; i--) { // 第i个物品 if(dp[i][j] > dp[i-1][j]) { isLoad[i] = 1; j -= weight[i]; } else { isLoad[i] = 0; } } return dp[n][w]; } int main() { int n = 3; int w = 4; int weight[4] = {0,2,1,3}; int value[4] = {0,4,2,3}; // 下标从1开始 0下标不用 直接设置为0 int isLoad[4]; int maxValue = knapSack(n,w,weight,value,isLoad); cout<<"最大价值是"<



