Knapsack Problem Java

2025年5月7日 | 阅读7分钟

最显著的组合优化问题之一是背包问题 Java。背包问题有两种类别。

  • 0-1 背包问题
  • 分数背包问题

让我们来讨论一下它们。

0 - 1 背包问题

给定 n 个不同物品的价值和重量。需要将这些物品放入容量为 C 的背包中,使得背包的价值最大。同时,背包中所有物品的总重量不得超过容量 C。由于这是 0-1 背包问题;因此,不允许分割物品,即永远不能打碎任何给定的物品,要么不选它,要么选它(0-1 属性)。

Knapsack Problem Java

背包问题可以通过穷举搜索或动态规划来解决。

使用穷举搜索

穷举搜索意味着应用暴力方法。在此方法中,尝试所有物品的组合,并为每种组合计算价值。生成最大价值的组合就是答案。

以下程序使用递归实现暴力方法。

文件名: KnapsackExample.java

输出

The maximum value is: 220

解释:输入数组的映射方式是,对于物品 i,重量为 weight[i],其价值为 values[i]。在每次递归调用中,都会做出一个决定,该物品是否应包含在解决方案中。如果不包含该物品,我们将继续进行,而不考虑其价值。如果包含该物品,则背包的容量会减少该物品的重量,我们继续进行,并包含其价值。其他物品也以类似的方式处理。通过添加所包含物品的价值产生的最大价值就是我们的答案。

请注意,该方法不是很方便,因为它需要很长时间才能给出结果。该方法的时空复杂度为 O(2 ^ n),其中 n 是存在的元素数。

使用动态规划

之所以需要动态规划,是因为上述方法花费了大量时间来生成结果。因此,从长远来看,上述方法会失败。因此,我们需要寻找另一种方法,即动态规划。

文件名: KnapsackExample1.java

输出

The maximum value is: 220

解释:与第一种方法类似,这次我们也在包含和排除列表中的每个物品。然而,这次我们有 O(n^2) 的更好时空复杂度。这是因为,与上述方法不同,我们利用较小物品列表的解决方案来构建完整物品列表的解决方案(动态规划的属性)。因此,迭代次数较少。请注意,在两种方法中,我们完全排除了或包含了物品,从而遵循了 0-1 属性。

分数背包问题

分数背包问题与 0-1 背包问题类似。唯一的区别是可以部分选择一个物品。因此,给予了打破任何物品然后将其放入背包的自由,以便最大化背包中所有物品(无论是否打破)的总价值。

文件名: KnapsackExample1.java

输出

Maximum value that can be obtained is = 240.0

解释:贪心算法用于解决分数背包问题。在此方法中,我们首先考虑那些在消耗较少重量的同时能产生最大价值的物品。换句话说,那些价值/重量比最大的物品。因此,我们通过价值/重量比来对列表进行非递减排序。因此,价值/重量比最高的物品位于第一个索引,价值/重量比第二高的物品占据第二个索引,依此类推。