From a5a972e45bca396183e27d37b3cd45d685d78f1d Mon Sep 17 00:00:00 2001 From: Nhan Khong <49646896+ktrongnhan@users.noreply.github.com> Date: Mon, 15 Apr 2019 20:57:32 +0700 Subject: [PATCH 1/3] Update Knapsack.js The current method of finding a complete solution to 0/1 knapsack problem has many flaws in it. I find it more elegant to use an auxiliary matrix whose elements e[i, j] are determined by a simple rule: e[i, j] := true if taking item[i] solves the subproblem knapsack(item[0..1], j) where j denotes a capacity; otherwise e[i, j] := false --- .../sets/knapsack-problem/Knapsack.js | 43 ++++++------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/src/algorithms/sets/knapsack-problem/Knapsack.js b/src/algorithms/sets/knapsack-problem/Knapsack.js index d93e51a3bd..dc2fd1c82d 100644 --- a/src/algorithms/sets/knapsack-problem/Knapsack.js +++ b/src/algorithms/sets/knapsack-problem/Knapsack.js @@ -75,6 +75,9 @@ export default class Knapsack { const knapsackMatrix = Array(numberOfRows).fill(null).map(() => { return Array(numberOfColumns + 1).fill(null); }); + const isItemTaken = Array(numberOfRows).fill(false).map(() => { + return Array(numberOfColumns + 1).fill(false); + }); // Fill the first column with zeros since it would mean that there is // no items we can add to knapsack in case if weight limitation is zero. @@ -89,6 +92,7 @@ export default class Knapsack { const itemWeight = this.possibleItems[itemIndex].weight; const itemValue = this.possibleItems[itemIndex].value; knapsackMatrix[itemIndex][weightIndex] = itemWeight <= weightIndex ? itemValue : 0; + isItemTaken[itemIndex][weightIndex] = (knapsackMatrix[itemIndex][weightIndex] !== 0); } // Go through combinations of how we may add items to knapsack and @@ -111,42 +115,19 @@ export default class Knapsack { currentItemValue + knapsackMatrix[itemIndex - 1][weightIndex - currentItemWeight], knapsackMatrix[itemIndex - 1][weightIndex], ); + + isItemTaken[itemIndex][weightIndex] = (knapsackMatrix[itemIndex][weightIndex] + !== knapsackMatrix[itemIndex - 1][weightIndex]); } } } - // Now let's trace back the knapsack matrix to see what items we're going to add - // to the knapsack. - let itemIndex = this.possibleItems.length - 1; - let weightIndex = this.weightLimit; - - while (itemIndex > 0) { - const currentItem = this.possibleItems[itemIndex]; - const prevItem = this.possibleItems[itemIndex - 1]; - - // Check if matrix value came from top (from previous item). - // In this case this would mean that we need to include previous item - // to the list of selected items. - if ( - knapsackMatrix[itemIndex][weightIndex] - && knapsackMatrix[itemIndex][weightIndex] === knapsackMatrix[itemIndex - 1][weightIndex] - ) { - // Check if there are several items with the same weight but with the different values. - // We need to add highest item in the matrix that is possible to get the highest value. - const prevSumValue = knapsackMatrix[itemIndex - 1][weightIndex]; - const prevPrevSumValue = knapsackMatrix[itemIndex - 2][weightIndex]; - if ( - !prevSumValue - || (prevSumValue && prevPrevSumValue !== prevSumValue) - ) { - this.selectedItems.push(prevItem); - } - } else if (knapsackMatrix[itemIndex - 1][weightIndex - currentItem.weight]) { - this.selectedItems.push(prevItem); - weightIndex -= currentItem.weight; + let capacity = this.weightLimit; + for (let itemIndex = this.possibleItems.length - 1; itemIndex >= 0; itemIndex -= 1) { + if (isItemTaken[itemIndex][capacity]) { + this.selectedItems.push(this.possibleItems[itemIndex]); + capacity -= this.possibleItems[itemIndex].weight; } - - itemIndex -= 1; } } From b23accf9b165482e35d66b7952f526eeca6b49f2 Mon Sep 17 00:00:00 2001 From: Nhan Khong <49646896+ktrongnhan@users.noreply.github.com> Date: Mon, 15 Apr 2019 21:01:34 +0700 Subject: [PATCH 2/3] Update Knapsack.test.js --- .../__test__/Knapsack.test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js index d322445a72..e4fd139344 100644 --- a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js +++ b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js @@ -22,6 +22,27 @@ describe('Knapsack', () => { expect(knapsack.selectedItems[0].toString()).toBe('v5 w4 x 1'); expect(knapsack.selectedItems[1].toString()).toBe('v4 w3 x 1'); }); + + it('should solve 0/1 knapsack problem in another trivial case', () => { + const possibleKnapsackItems = [ + new KnapsackItem({ value: 3, weight: 2 }), + new KnapsackItem({ value: 4, weight: 3 }), + new KnapsackItem({ value: 5, weight: 4 }), + new KnapsackItem({ value: 7, weight: 5 }), + ]; + + const maxKnapsackWeight = 7; + + const knapsack = new Knapsack(possibleKnapsackItems, maxKnapsackWeight); + + knapsack.solveZeroOneKnapsackProblem(); + + expect(knapsack.totalValue).toBe(10); + expect(knapsack.totalWeight).toBe(7); + expect(knapsack.selectedItems.length).toBe(2); + expect(knapsack.selectedItems).toContain(possibleKnapsackItems[0]); + expect(knapsack.selectedItems).toContain(possibleKnapsackItems[3]); + }); it('should solve 0/1 knapsack problem regardless of items order', () => { const possibleKnapsackItems = [ From 95a75fb7e249b181f2b9488d0ae9aea496e12fa0 Mon Sep 17 00:00:00 2001 From: Nhan Khong <49646896+ktrongnhan@users.noreply.github.com> Date: Mon, 15 Apr 2019 21:28:00 +0700 Subject: [PATCH 3/3] Update Knapsack.test.js --- src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js index e4fd139344..f8d2a1aba2 100644 --- a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js +++ b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js @@ -22,7 +22,7 @@ describe('Knapsack', () => { expect(knapsack.selectedItems[0].toString()).toBe('v5 w4 x 1'); expect(knapsack.selectedItems[1].toString()).toBe('v4 w3 x 1'); }); - + it('should solve 0/1 knapsack problem in another trivial case', () => { const possibleKnapsackItems = [ new KnapsackItem({ value: 3, weight: 2 }),