我发现背包问题既棘手又有趣。 我敢肯定,如果您正在访问此页面,您已经知道了问题说明,但是只是为了完成本章:
问题:
给定一个最大容量为W和N的背包,每个背包都有自己的值和重量,将它们放入背包中,使最终内容物具有最大值。 kes!
这是解释问题的一般方法-考虑一个小偷进入家中抢劫,他背着背包。 家里有固定数量的物品-每个物品都有自己的重量和价值-珠宝首饰,重量和重量比桌子高,价值少,但重量重。 为了给火上加油,小偷有一个老式的背包,容量有限。 显然,他不能将桌子分成两半,也不能将珠宝分成3/4分。 他要么接受要么离开。
范例:
Knapsack Max weight : W = 10 (units)
Total items : N = 4
Values of items : v[] = {10, 40, 30, 50}
Weight of items : w[] = {5, 4, 6, 3}
粗略看一下示例数据可知,在权重最大为10的情况下,我们可以容纳的最大值为50 + 40 = 90(权重为7)。
方法:
最佳解决方案是使用动态编程-解决较小的背包问题,然后将其扩展为较大的问题。
让我们构建一个名为V(值数组)的Item x Weight数组:
V[N][W] = 4 rows * 10 columns
此矩阵中的每个值代表一个较小的背包问题。
基本情况1 :让我们以第0列为例。 这仅意味着背包的容量为0。 你能在他们身上抱什么? 没有。 因此,让我们用0填充它们。
基本情况2 :让我们以0行为例。 这仅表示房子中没有物品。 如果没有物品,您在背包里会做什么? 没事了! 全零。
解:
- 现在,让我们开始逐行填充数组。 第1行和第1列是什么意思? 给定第一个项目(行),您能否将其容纳在容量为1(列)的背包中。 不。 第一项的权重为5。因此,让我们填写0。实际上,直到到达第5列(权重5),我们才能填写任何内容。
- 当我们到达第一行的第5列(代表权重5)时,这意味着我们可以容纳第1项。让我们在此处填写10(请记住,这是一个Value数组):
- 继续,对于权重6(第6列),我们是否可以容纳剩余重量为1(重量–该商品的重量=> 6 – 5)的任何其他东西。 嘿,记住,我们在第一个项目上。 因此,从直觉上讲,该行的其余部分也将是相同的值,因为我们无法为已获得的额外重量添加任何其他项目。
- 因此,当我们到达第三行的第4列时,会发生下一个有趣的事情。 当前的跑步重量为4。
我们应检查以下情况。
- 我们可以容纳项目2 –是的,我们可以。 项目2的权重为4。
- 没有第2项,当前重量的值是否更高? –检查上一行是否具有相同的重量。 不。 前一行*的内容为0,因为我们无法容纳重量为4的商品1。
- 我们可以容纳两件重量相同的物品,以使价值最大化吗? - 不。 减去Item2的权重后的剩余权重为0。
为什么要上一行?
仅仅是因为权重为4的前一行本身是一个较小的背包解决方案,它给出了该权重在该点之前(穿越项目)可以累积的最大值。
举例说明
- 当前项目的值= 40
- 当前商品的重量= 4
- 剩下的权重= 4 – 4 = 0
- 检查上面的行(如果是项目1,则检查上面的项目;如果其余的行,则检查累积最大值)。 对于剩余重量0,我们是否可以容纳项目1? 简而言之,对于给定的权重,上面一行是否有任何值?
计算过程如下:
- 不带此项,取相同重量的最大值:
previous row, same weight = 0 => V[item-1][weight]
- 取当前商品的价值+我们可以用剩余重量容纳的价值:
Value of current item + value in previous row with weight 4 (total weight until now (4) - weight of the current item (4)) => val[item-1] + V[item-1][weight-wt[item-1]]
两者之间的最大值为40(0和40)。
- 下一个也是最重要的事件发生在第9列和第2行。这意味着我们的权重为9,并且有两项。 查看示例数据,我们可以容纳前两个项目。 在这里,我们考虑几件事:
1. The value of the current item = 40 2. The weight of the current item = 4 3. The weight that is left over = 9 - 4 = 5 4. Check the row above. At the remaining weight 5, are we able to accommodate Item 1.
因此,计算公式为:
- 不带此项,取相同重量的最大值:
previous row, same weight = 10
- 取当前商品的价值+我们可以用剩余重量累计的价值:
Value of current item (40) + value in previous row with weight 5 (total weight until now (9) - weight of the current item (4)) = 10
10比50 = 50。
解决所有这些较小的问题之后,我们只需要返回权重为10的V [N] [W] –项目4的值:
复杂
分析解决方案的复杂性非常简单。 我们在N => O(NW)的循环中只有一个W循环
实现方式:
这是Java中的强制性实现代码:
class Knapsack {
public static void main(String[] args) throws Exception {
int val[] = {10, 40, 30, 50};
int wt[] = {5, 4, 6, 3};
int W = 10;
System.out.println(knapsack(val, wt, W));
}
public static int knapsack(int val[], int wt[], int W) {
//Get the total number of items.
//Could be wt.length or val.length. Doesn't matter
int N = wt.length;
//Create a matrix.
//Items are in rows and weight at in columns +1 on each side
int[][] V = new int[N + 1][W + 1];
//What if the knapsack's capacity is 0 - Set
//all columns at row 0 to be 0
for (int col = 0; col <= W; col++) {
V[0][col] = 0;
}
//What if there are no items at home.
//Fill the first row with 0
for (int row = 0; row <= N; row++) {
V[row][0] = 0;
}
for (int item=1;item<=N;item++){
//Let's fill the values row by row
for (int weight=1;weight<=W;weight++){
//Is the current items weight less
//than or equal to running weight
if (wt[item-1]<=weight){
//Given a weight, check if the value of the current
//item + value of the item that we could afford
//with the remaining weight is greater than the value
//without the current item itself
V[item][weight]=Math.max (val[item-1]+V[item-1][weight-wt[item-1]], V[item-1][weight]);
}
else {
//If the current item's weight is more than the
//running weight, just carry forward the value
//without the current item
V[item][weight]=V[item-1][weight];
}
}
}
//Printing the matrix
for (int[] rows : V) {
for (int col : rows) {
System.out.format("%5d", col);
}
System.out.println();
}
return V[N][W];
}
}
翻译自: https://www.javacodegeeks.com/2014/07/the-knapsack-problem.html