一、01背包
1. 二维dp数组01背包
有n件物品和1个最多能背重量w的背包,第i件物品的重量是weight[i],得到的价值为value[i],每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大
暴力解法
每个物品的状态是取或者不取,通过回溯搜索出所有的情况,那时间复杂度就是o(2^n), 指数级别,所有需要动态规划来优化
动态规划五部曲
- 确定dp数组,
dp[i][j],表示从0-i的物品里任意取,放进容量为j的背包,价值总和最大是多少 - 确定递推公式,
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i]) - dp数组初始化
- 当j为0,
dp[i][0] = 0 - 当i为0,当
j < weight[0]dp[0][j] = 0,容量太小放不进去 - 当i为0,当
j >= weight[0]dp[0][j] = value[0],容量可以放进去0的物品
- 当j为0,
- 遍历顺序
let inputArr = [
[6, 1],
[2, 2, 3, 1, 5, 2],
[2, 3, 1, 5, 4, 3]
];
function fun(inputArr) {
let [M, N] = inputArr[0]
let weight = inputArr[1]
let value = inputArr[2]
let dp = new Array(M).fill(0).map(_ => new Array(N + 1).fill(0))
for (let j = weight[0]; j <= N; j++) {
dp[0][j] = value[0]
}
for (let i = 1; i < M; i++) {
for (let j = 0; j <= N; j++) {
if (j < weight[i]) {
dp[i][j] = dp[i - 1][j]
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
}
}
}
return dp[M - 1][N]
}
console.log(fun(inputArr))
2. 一维dp数组(滚动数组)
五部曲
- dp数组的含义,容量为j的背包,所背物品的最大价值
- 确定递推公式,
dp[j] = Math.max(dp[j], dp[j - weight[i]]) + value[i] - dp初始化
dp[0] = 0 - 遍历顺序,必须是从后往前,对于二维dp,
dp[i][j]是根据dp[i-1][j]计算而来,一维dp,倒序遍历是为了保证左边的值依旧是上一层的状态,不会重复计算 - 举例
let inputArr = [
[6, 1],
[2, 2, 3, 1, 5, 2],
[2, 3, 1, 5, 4, 3]
];
function fun(inputArr) {
let [M, N] = inputArr[0]
let weight = inputArr[1]
let value = inputArr[2]
let dp = new Array(N + 1).fill(0)
dp[0] = 0
for (let i = 0; i < M; i++) {
for(let j = N; j >= weight[i]; j--) {
dp[j] = Math.max(dp[j], dp[j-weight[i]] + value[i])
}
}
return dp[N]
}
console.log(fun(inputArr))
二、分割等和子集
可以转换为01背包问题,背包的体积为 sum / 2,背包能够放的最大和等于背包大小的时候,为true
五部曲
dp[j],容量为j的背包,能够容纳的最大价值,j为目标和,dp[j]是最大和- 递归公式:
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]) - dp初始化
dp[0] = 0 - 遍历顺序
- 举例
/**
* @param {number[]} nums
* @return {boolean}
*/
var canPartition = function(nums) {
let sum = nums.reduce((sum, cur) => sum + cur)
if(sum % 2 === 1) {
return false
}
let target = sum / 2
let dp = new Array(target + 1).fill(0)
for(let i = 0; i < nums.length;i++) {
for(let j = target; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i])
}
}
return dp[target] === target
};