0/1 最低成本背包
0/1 Knapsack with Minimum Cost
著名的0/1
背包问题的重点是在给定的Weight (W)
.
中得到最大值cost/value
上面的代码是这样的::
n = cost_array / weight_array size
INIT :: fill 0th col and 0th row with value 0
for (int i=1; i<=n; i++) {
for (int j=1; j<=W; j++) {
if (weight[i-1] <= j) {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - weight[i-1]] + cost[i-1]);
}else {
dp[i][j] = dp[i-1][j];
}
}
}
答案:: dp[n][W]
新问题 :: 因此,我们在这里计算最大值 cost/value。但是,如果我想找到最小值 cost/value 怎么办(它仍然仅限背包)。
我认为问题归结为我如何执行上面的 INIT
步骤。正如在循环中一样,我认为它将保持不变,唯一的区别是 Math.max
变为 Math.min
我用 Infinity
、0
等尝试了 INIT
步骤,但无法构建迭代解决方案。
我们怎么可能那样做?
写@radovix提到的答案
- 将每个权重转换为负数并编写相同的算法。
这是一个用 JS 编写的有效算法(最小成本最大背包),时间复杂度为 O(nC) 和 space 复杂度为 O(n+C),而不是 [= 的明显解决方案19=] 具有 DP 矩阵的复杂度 O(nC)。
给定一个背包实例 (I, p,w, C),MCMKP(Minimum-Cost Maximal Knapsack Packing)的目标是找到一个最大的背包包装 S⊂I,使所选物品的利润最小化
const knapSack = (weights, prices, target, ic) => {
if (weights.length !== prices.length) {
return null;
}
let weightSum = [0],
priceSum = [0];
for (let i = 1; i < weights.length; i++) {
weightSum[i] = weights[i - 1] + weightSum[i - 1];
priceSum[i] = prices[i - 1] + priceSum[i - 1];
}
let dp = [0],
opt = Infinity;
for (let i = 1; i <= target; i++) dp[i] = Infinity;
for (let i = weights.length; i >= 1; i--) {
if (i <= ic) {
const cMax = Math.max(0, target - weightSum[i - 1]),
cMin = Math.max(0, target - weightSum[i - 1] - weights[i - 1] + 1);
let tmp = Infinity;
for (let index = cMin; index <= cMax; index++) {
tmp = Math.min(tmp, dp[index] + priceSum[i - 1]);
}
if (tmp < opt) opt = tmp;
}
for (let j = target; j >= weights[i - 1]; j--) {
dp[j] = Math.min(dp[j], dp[j - weights[i - 1]] + prices[i - 1]);
}
}
return opt;
};
knapSack([1, 1, 2, 3, 4],[3, 4, 6, 2, 1],5,4);
在上面的以下代码中,我们将关键项目定义为一个项目,其权重给出了任何可行解决方案中遗漏的最小可能项目的严格上限。
关键项的索引,即第一个超出容量的项的索引,假设所有 i ≤ ic
也会被带走。 opt 是最优解。
观察项目 {1, . . . , i − 1} 确定背包的剩余容量
(以 cMax 形式给出)必须使用来自 {i + 1, . . . , n}, 而 cMin 是由以下事实决定的:包装必须是最大的,而第 i 项是从解决方案中取出的最小项
著名的0/1
背包问题的重点是在给定的Weight (W)
.
上面的代码是这样的::
n = cost_array / weight_array size
INIT :: fill 0th col and 0th row with value 0
for (int i=1; i<=n; i++) {
for (int j=1; j<=W; j++) {
if (weight[i-1] <= j) {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j - weight[i-1]] + cost[i-1]);
}else {
dp[i][j] = dp[i-1][j];
}
}
}
答案:: dp[n][W]
新问题 :: 因此,我们在这里计算最大值 cost/value。但是,如果我想找到最小值 cost/value 怎么办(它仍然仅限背包)。
我认为问题归结为我如何执行上面的 INIT
步骤。正如在循环中一样,我认为它将保持不变,唯一的区别是 Math.max
变为 Math.min
我用 Infinity
、0
等尝试了 INIT
步骤,但无法构建迭代解决方案。
我们怎么可能那样做?
写@radovix提到的答案
- 将每个权重转换为负数并编写相同的算法。
这是一个用 JS 编写的有效算法(最小成本最大背包),时间复杂度为 O(nC) 和 space 复杂度为 O(n+C),而不是 [= 的明显解决方案19=] 具有 DP 矩阵的复杂度 O(nC)。 给定一个背包实例 (I, p,w, C),MCMKP(Minimum-Cost Maximal Knapsack Packing)的目标是找到一个最大的背包包装 S⊂I,使所选物品的利润最小化
const knapSack = (weights, prices, target, ic) => {
if (weights.length !== prices.length) {
return null;
}
let weightSum = [0],
priceSum = [0];
for (let i = 1; i < weights.length; i++) {
weightSum[i] = weights[i - 1] + weightSum[i - 1];
priceSum[i] = prices[i - 1] + priceSum[i - 1];
}
let dp = [0],
opt = Infinity;
for (let i = 1; i <= target; i++) dp[i] = Infinity;
for (let i = weights.length; i >= 1; i--) {
if (i <= ic) {
const cMax = Math.max(0, target - weightSum[i - 1]),
cMin = Math.max(0, target - weightSum[i - 1] - weights[i - 1] + 1);
let tmp = Infinity;
for (let index = cMin; index <= cMax; index++) {
tmp = Math.min(tmp, dp[index] + priceSum[i - 1]);
}
if (tmp < opt) opt = tmp;
}
for (let j = target; j >= weights[i - 1]; j--) {
dp[j] = Math.min(dp[j], dp[j - weights[i - 1]] + prices[i - 1]);
}
}
return opt;
};
knapSack([1, 1, 2, 3, 4],[3, 4, 6, 2, 1],5,4);
在上面的以下代码中,我们将关键项目定义为一个项目,其权重给出了任何可行解决方案中遗漏的最小可能项目的严格上限。 关键项的索引,即第一个超出容量的项的索引,假设所有 i ≤ ic 也会被带走。 opt 是最优解。 观察项目 {1, . . . , i − 1} 确定背包的剩余容量 (以 cMax 形式给出)必须使用来自 {i + 1, . . . , n}, 而 cMin 是由以下事实决定的:包装必须是最大的,而第 i 项是从解决方案中取出的最小项