92. 背包问题
在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i]
样例
如果有4个物品[2, 3, 5, 7]
如果背包的大小为11,可以选择[2, 3, 5]装入背包,最多可以装满10的空间。
如果背包的大小为12,可以选择[2, 3, 7]装入背包,最多可以装满12的空间。
函数需要返回最多能装满的空间大小。
挑战
O(n x m) time and O(m) memory.
O(n x m) memory is also acceptable if you do not know how to optimize memory.
注意事项
你不可以将物品进行切割。
题目链接:https://www.lintcode.com/problem/backpack/description
昨天看了一天的动态规划的讲解,但是纸上得来终觉浅,所以今天打算进行刷题,希望能够搞懂这一类题目的做法。
解题思路:解决动态规划问题,最重要的是列出状态方程,列出来之后,问题就差不多解决了一半了。自己看了这么多的基础知识讲解,遇上之后还是有点束手无策。我想到的是对i个变量“选还是不选”,于是我开始沿着自己的思路往下做,画了一颗二叉树(就是选还是不选)。但是自己画的这个二叉树实在过于庞大(数据大的话,无法形容)而且特别复杂。肯定是自己在思路上有了差错。
自己实在做不出来,就去网上百度了一下大佬的思路。在这里分享一下:
本题是典型的01背包问题,每种类型的物品最多只能选择一件。
1.状态: result[i][S] 表示前i个物品,取出一些物品能否组成体积和为S的背包
2.状态转移方程: f[i][S]=f[i−1][S−A[i]] or f[i−1][S] (A[i]为第i个物品的大小)
1.欲从前i个物品中取出一些组成体积和为S的背包,可从两个状态转换得到。
i.f[i−1][S−A[i]]:放入第i个物品,前i−1 个物品能否取出一些体积和为 S−A[i] 的背包。
ii.f[i−1][S]:不放入第i个物品,前i−1 个物品能否取出一些组成体积和为S的背包。
3.状态初始化: f[1⋯n][0]=true; f[0][1⋯m]=false. 前1~n个物品组成体积和为0的背包始终为真,其他情况为假。
4.返回结果: 寻找使 f[n][S] 值为true的最大S (1≤S≤m)
来源:https://zhuanlan.zhihu.com/p/32001408
根据思路,状态方程如下:
自己的代码:
public static int dp_bag(int[] arr,int m){
int len = arr.length;
int[][] bag_arr = new int[len][m+1];
for(int i=0;i<len;i++)
bag_arr[i][0] = 0;//背包的容量为0时,肯定不能放任何东西
for(int j = 1;j<m+1;j++){
if(arr[0]>j)//对i=0提前处理,防止发生数组越界问题
bag_arr[0][j] = 0;
else
bag_arr[0][j] = arr[0];
for(int i=1;i<len;i++){
if(arr[i]>j){
bag_arr[i][j] = bag_arr[i-1][j];
}else{
bag_arr[i][j] = Math.max(bag_arr[i-1][j-arr[i]]+arr[i],bag_arr[i-1][j]);
}
}
}
/*for(int i=0;i<len;i++){
for(int j=0;j<m+1;j++)
System.out.print(bag_arr[i][j]+" ");
System.out.println();
}*/
return bag_arr[len-1][m];
}
别人的代码:
public class Solution {
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
public int backPack(int m, int[] A) {
boolean f[][] = new boolean[A.length + 1][m + 1];
for (int i = 0; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = false;
}
}
f[0][0] = true;
for (int i = 1; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];
if (j >= A[i-1] && f[i-1][j - A[i-1]]) {
f[i][j] = true;
}
} // for j
} // for i
for (int i = m; i >= 0; i--) {
if (f[A.length][i]) {
return i;
}
}
return 0;
}
}
// O(m) 空间复杂度的解法
public class Solution {
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
public int backPack(int m, int[] A) {
int f[] = new int[m + 1];
for (int i = 0; i < A.length; i++) {
for (int j = m; j >= A[i]; j--) {
f[j] = Math.max(f[j], f[j - A[i]] + A[i]);
}
}
return f[m];
}
}