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; } } diff --git a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js index d322445a72..f8d2a1aba2 100644 --- a/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js +++ b/src/algorithms/sets/knapsack-problem/__test__/Knapsack.test.js @@ -23,6 +23,27 @@ describe('Knapsack', () => { 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 = [ new KnapsackItem({ value: 5, weight: 4 }),