在不断增加的背包中选取物品,以达到当前背包当前能够选取的物品的最大值,分割等和子集道理和背包一样。
let w = 10,
W = [2, 3, 5, 7],
V = [3, 4, 6, 18];
let res = 0
const wl = W.length;
let dp = new Array(wl + 1).fill(0).map((e) => new Array(w + 1).fill(0));
//初始化第一个:什么都不选 ,是对于第一个物品都选不了的情况。 第二个初始化:是背包装不下了
for (let i = 1; i <= wl; i++) {
const t = i - 1;
for (let j = 1; j <= w; j++) {
if (j - W[t] < 0) {
dp[i][j] = dp[t][j];
} else {
dp[i][j] = Math.max(dp[t][j - W[t]] + V[t], dp[t][j]);
}
}
}
res = dp[wl][w]
console.log(dp);
console.log(res);
//下面这个一样
let dp = new Array(w + 1).fill(0).map((e) => new Array(wl + 1).fill(0));
for (let i = 1; i <= w; i++) {
for (let j = 1; j <= wl; j++) {
const t = j - 1;
if (i - W[t] < 0) {
dp[i][j] = dp[i][t];
} else {
dp[i][j] = Math.max(dp[i - W[t]][t] + V[t], dp[i][t]);
}
}
}
console.log(dp);
降维处理
let dp = new Array(w + 1).fill(0) // dp【j】中的每个值代表在j容量的时候的最大值,容量为0的时候必然最大值为零
for (let i = 1; i <= w; i++) { //现在是以重量为第一层
for (let j = 0; j < wl; j++) { //如果这样处理的话 那么始终会导致重复选取 就比如说 当i=2 => dp【2】 =3
// 那么 i=4 的时候会 还是选从背包中选取第一个 导致dp【4】=6 故就不能以重量来作为第一层
if (i - W[j] >= 0) {
dp[i] = Math.max(dp[i - W[j]] + V[j], dp[i - 1], dp[i])
}
}
}
考虑重量作为第二层,因为dp【j】中的每个值代表在j容量的时候的最大值,j又越来越大
,对于每一个物品,依然考虑选与不选,那么没法判断以前选过没有,故考虑在背包越来越小的时候我们去找最大值。
let dp = new Array(w + 1).fill(0) // dp【j】中的每个值代表在j容量的时候的最大值,容量为0的时候必然最大值为零
for (let i = 0; i < wl; i++) {
for (let j = w; j > 0; j--) {
if (j >= W[i]) {//这样写好理解些
dp[j] = Math.max(dp[j - W[i]] + V[i], dp[j])//相当于滚动数组 又相当于选与不选
}
}
}
console.log(dp);
分割等和⼦集 道理和背包问题一样
let W = [1, 3, 5, 1, 62, 6, 2, 6, 26, 2, 6, 2, 62, 6, 2, 1];
function aa() {
let w = W.reduce((a, b) => a + b) / 2
if (Math.floor(w) - w < 0) return false
const wl = W.length;
let dp = new Array(wl + 1).fill(0).map((e) => new Array(w + 1).fill(0));
for (let i = 1; i <= wl; i++) {
const t = i - 1;
for (let j = 1; j <= w; j++) {
if (j - W[t] <0) {
dp[i][j] = dp[t][j]
}else{
dp[i][j]=Math.max(dp[t][j - W[t]] + W[t], dp[t][j]);
}
if (dp[i][j] === w) {
return true
}
}
}
console.log(dp);
return w === dp[wl][w]
}
console.log(aa());
目标和来源于leetcode,放在这里是提醒: dp[0][0] = 1;
dp[i][j] = dp[i - 1][j];
if (j >= num) {
dp[i][j] += dp[i - 1][j - num];
}
这种情况,在每一步不是求极值,而是求和
let W = [1, 1, 1, 1, 2];
s = 2
var findTargetSumWays = function (nums, target) {
let sum = 0;
for (const num of nums) {
sum += num;
}
const diff = sum - target;
if (diff < 0 || diff % 2 !== 0) {
return 0;
}
const n = nums.length,
neg = diff / 2;
console.log(neg);
const dp = new Array(n + 1).fill(0).map(() => new Array(neg + 1).fill(0));
dp[0][0] = 1;
for (let i = 1; i <= n; i++) {
const num = nums[i - 1];
for (let j = 0; j <= neg; j++) {
dp[i][j] = dp[i - 1][j];
if (j >= num) {
dp[i][j] += dp[i - 1][j - num];
}
}
}
console.log(dp);
return dp
};
findTargetSumWays(W, s)