目录
题目
描述
在 n
个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m
,每个物品的大小为AiAi
(每个物品只能选择一次且物品大小均为正整数)
样例
样例 1:
输入:
数组 = [3,4,8,5]
backpack size = 10
输出:
9
解释:
装4和5.
样例 2:
输入:
数组 = [2,3,5,7]
backpack size = 12
输出:
12
解释:
装5和7.
解析
暴力解法
首先先思考这道题的一个暴力解法,对于一个物品,它只有取或者不去两种可能,这样进行dfs进行递归,记录下每种情况的最大值,总的时间复杂度就为2的n次方。
动态规划解法
然后我们再思考如何使用dp动态规划来解决这道题目。
递推公式
dp[i][j]
表示的是下标为0到i的物品任取然后放进容量为j的背包里总的价值
不放物品i表示的最大价值为dp[i-1][j]
放物品i则为dp[i - 1][j - weight[i]] + value[j]
所以递推公式为:dp[i][j] = max(dp[i-1][j],dp[i - 1][j - weight[i]] + value[j])
dp数组初始化
由递推公式可知,当前数组的值是由它上面和它左上角的元素推导出来的
首先初始化第一列,因为背包总容量为0,所以一个物品都装不了,总价值为0,所以第一列的值都为0
对于第一行,只能装物品0,如果容量大于物品0的重量就装,否则就为0
遍历顺序
一般默认是先遍历物品,再遍历背包,两重for循环
但对于二维dp来说,先遍历背包容量,再遍历物品也是OK的,因为dp是由它上面那个元素和它左上角的元素得到的,无论是按行逐行遍历,还是按列逐列遍历,都可以得到正确的dp数组。
代码
初始化行和列,然后推导dp数组时进行判断如果j>=a[i]再进行max进行推导。
class Solution {
public:
/**
* @param m: An integer m denotes the size of a backpack
* @param a: Given n items with size A[i]
* @return: The maximum size
*/
int backPack(int m, vector<int> &a) {
// write your code here
if(a.size() == 0 || m == 0)
return 0;
//如果背包没容量或者没物品,最大值肯定为0
//就不用动态规划了
int n = a.size();
const int N = 1e5 + 10;
int dp[1010][N];
//初始化dp数组的行和列
//横坐标为物品编号,纵坐标为背包容量
for(int j = 0; j <= m; j++) {
if(j >= a[0])
dp[0][j] = a[0];
else
dp[0][j] = 0;
}
for(int i = 0; i < n; i++)
dp[i][0] = 0;
//没容量,一个物品都装不了,总价值肯定为0
for(int i = 1; i < n; i++) {
for(int j = 0; j <= m; j++) {
if(j >= a[i])
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + a[i]);
else
dp[i][j] = dp[i - 1][j];
}
}
return dp[a.size() - 1][m];
}
};