货箱装载
有 n 个货箱, 重量分别为 w1 w2 w3 ... 货船能载重 c 问如何装箱, 才能装下更多的货箱
贪婪算法
每次选出 重量最小 的货箱, 这样就能够保证装载数量最大
function containerLoading(container, capacity) {
// 按照重量进行升序
let c = container.map((e, i) => {
return {
weight: e,
id: i,
};
});
c.sort((a, b) => a.weight - b.weight);
let res = new Array(container.length).fill(0);
// 每次选出重量最小的货箱, 直到超重
for (let i = 0; i < c.length && c[i].weight <= capacity; i++) {
res[c[i].id] = 1;
capacity -= c[i].weight;
}
return res;
}
// 货箱重量
let container = [100, 200, 50, 90, 150, 50, 20, 80];
// 装载结果
let res = containerLoading(container, 400);
console.log(res);
0/1背包问题
有 n 个物品和一个容量为 c 的背包, 每个物品重量为 w(i) ,价值 p(i) , 如何装包才能使得物品重量不超过背包容量且装入的物品价值最大(每个物品至多选 1 次)
贪婪算法
function backpack(container, capacity) {
let c = container.map((e, i) => {
return {
...e,
id: i,
per: e.profit / e.weight,
};
});
// 按照单位质量价值降序
c.sort((a, b) => b.profit / b.weight - a.profit / a.weight);
let res = new Array(container.length).fill(0);
// 优先选取单价大的, 直到装满
let profit = 0;
for (let i = 0; i < c.length; i++) {
if (c[i].weight <= capacity) {
res[c[i].id] = 1;
capacity -= c[i].weight;
profit += c[i].profit;
}
}
return {
profit,
res,
};
}
// 背包重量和价值
let container = [
{
weight: 10,
profit: 40,
},
{
weight: 30,
profit: 40,
},
{
weight: 25,
profit: 30,
},
{
weight: 50,
profit: 50,
},
{
weight: 40,
profit: 35,
},
{
weight: 60,
profit: 30,
},
{
weight: 35,
profit: 10,
},
];
// 装载结果
let res = backpack(container, 150);
console.log(res);
递归算法
function backpack(container, capacity) {
/**
* @param {*} i 剩余物品 i, i+1, ..., n
* @param {*} capacity 剩余容量
* @param {*} container 物品
* @returns 当前背包价值
*/
function pack(i, capacity, container) {
if (i == container.length - 1) {
// 最后一个物品, 如果超了就不放, 不超就放
return capacity < container[i].weight ? 0 : container[i].profit;
} else if (capacity < container[i].weight) {
// 不是最后一个商品, 物品重量超过容量, 直接丢弃, 继续看下一个物品
return pack(i + 1, capacity, container);
} else {
// 当前物品还在容量范围内
// 放第 i 件商品的价值
let p1 = pack(i + 1, capacity - container[i].weight, container) + container[i].profit;
// 不放第 i 件商品的价值
let p2 = pack(i + 1, capacity, container);
return Math.max(p1, p2);
}
}
return pack(0, capacity, container);
}
相关问题:
// sum(+) - sum(-) = target
// => sum(nums) + sum(+) - sum(-) = sum(nums) + target
// => 2 × sum(+) = sum(nums) + target
// => sum(+) = (sum(nums) + target) / 2
// 变成容量为 sum(+) 的背包问题
var findTargetSumWays = function (nums, target) {
// 计算 nums 和
let sum = nums.reduce((pre, cur) => pre + cur, 0);
if (sum < Math.abs(target) || (sum + target) % 2 == 1) return 0;
let capacity = (sum + target) / 2;
let dp = new Array(capacity + 1).fill(0);
dp[0] = 1; // sum(+)=0 时的解法数
nums.forEach(num => { // 遍历物品
// 从后往前遍历, 一直遍历到 num
// 也就是 sum(+)=j 的解法数等于 sum(+)=j-num 的解法数之和
// 因为 sum(j-num) 的全部解法, 最后加一个 num 刚好等于 j
// 比如 sum(+)=4 的解法数可以等于 sum(+)=5-1, sum(+)=6-2 等等的解法数之和
for (let j = capacity; j >= num; j--) {
dp[j] += dp[j - num];
}
});
return dp[capacity];
};
console.log(findTargetSumWays([100], -200));