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 }),