算法:背包问题
一、题目
背包问题指的是给定2个数组,分别表示一组物品的容量和价值。给定一个背包容量。问在不超过背包容量的前提下能装的物品的最大价值。
背包问题细分有:
- 01背包问题
- 完全背包问题
- 多重背包问题
- 其他组合背包问题
主要区分在放入物品的数量的限制上。比如01背包问题只能放或者不放1个;完全背包不限制数量;多重背包限制指定数量等。
实际面试场景中都是背包问题的变种,考察的是掌握背包问题在实际场景中的灵活运用。
本文主要介绍01背包问题和完全背包问题。
二、输入
- 两个相同大小的数组。数组长度对应物品的数量,数组分别对应物品的容量和价值。
- 待放入物品的背包总容量
- 物品的数量(可选)
注意物品的容量有的地方也理解为重量,两者可以互换
三、输出
装入物品的最大价值
四、示例
1 | 输入: |
五、题解
- 背包问题大家都知道是动态规划的经典案例。动态规划本质是从遍历所有解找最优子结构,重复子问题降低复杂度。动态规划解答前最好了解暴搜遍历的方法。对应这里的是回溯算法(选还是不选)
- 动态规划解法先从2维动态数组理解,再考虑一维滚动数组的优化
- dp[i][j]表示从0~i件物品中选择,背包容量不超过j时背包的最大价值
- dp[j]表示背包容量不超过j时背包的最大价值
- 01背包和完全背包的转移方程有小的差别,原因是完全背包中同一个物品可以多次选择。
01背包:dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i]] + v[i];
完全背包:dp[i][j] = Math.max(dp[i-1][j], dp[i][j-w[i]] + v[i] - 二维动态数组优化为一维数组时需要注意遍历的顺序。01背包问题需要从背包容量最大值到最小值,避免同一件物品被重复计算(放入包中)。二维动态数组没有这个问题,因为第i-1个物品对应的dp值已经被固化,不会被覆盖了
- 背包问题2层循环一般外层遍历物品,内层遍历背包容量。对于2维动态数组2层循环遍历顺序影响不大;对于1维动态数组解决01背包问题要求外层先遍历物品
5.1 01背包 Java 实现
1 | package org.stone.study.algo.dp; |
5.2 完全背包 Java 实现
1 | package org.stone.study.algo.dp; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 石头记!