Skip to content

Commit b2c8004

Browse files
committed
Create dynamic knapsack algo
Attempt to liberate the best combination of items from a house you're burgling with a knapsack weight constraint for the highest value. - Considering the items weights & values; traverse vertically through a matrix (2d array) of sub-problems to find the optimal combination of items to boost.
1 parent bbff323 commit b2c8004

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

dynamicKnapsack.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const dynamicKnapsack = function(weightCap, weights, values) {
2+
const numItem = weights.length;
3+
const matrix = new Array(numItem);
4+
5+
for (let index = 0; index <= numItem; index++) {
6+
matrix[index] = new Array(weightCap + 1);
7+
for (let weight = 0; weight <= weightCap; weight++) {
8+
if (index === 0 || weight === 0) {
9+
matrix[index][weight] = 0;
10+
// else if the weight of element at index - 1 <= weight:
11+
} else if (weights[index-1] <= weight) {
12+
// find possible values of including and excluding the item
13+
const prevItemsValue = matrix[index - 1][weight];
14+
const currItemsWeight = weights[index - 1];
15+
const currItemsValue = values[index - 1];
16+
const availWeight = weight - currItemsWeight;
17+
const prevItems = matrix
18+
.map((item, i) => {
19+
// return prev item values without overflowing knapsack
20+
return item[availWeight]
21+
&& i !== index // Exclude current items row
22+
? item[availWeight]
23+
: 0
24+
});
25+
26+
console.log('ROW:', index, 'COL:', weight, 'currItemsValue:',
27+
currItemsValue, '\n', 'prevItems (avail):', prevItems, 'MAX:',
28+
prevItems.reduce((a, b) => {return Math.max(a, b)}, -Infinity),
29+
'\n',);
30+
31+
// set element at [index][weight] to max of those values
32+
matrix[index][weight] = Math.max(
33+
prevItemsValue,
34+
currItemsValue,
35+
prevItems.reduce(
36+
(a, b) => {
37+
return Math.max(a, b)
38+
}, -Infinity) + currItemsValue
39+
)
40+
41+
} else { // item weight > weight
42+
// set element at [index][weight] to element one above
43+
matrix[index][weight] = matrix[index-1][weight];
44+
}
45+
}
46+
}
47+
console.log('=>', matrix[numItem][weightCap]);
48+
return matrix[numItem][weightCap];
49+
};
50+
51+
export default dynamicKnapsack;
52+

dynamicKnapsack.test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// import {describe, it} from 'node:test';
2+
import assert from 'node:assert/strict';
3+
import {jest} from '@jest/globals';
4+
import util from 'node:util';
5+
import {style} from './styles.js';
6+
util.inspect.defaultOptions.depth = null; // show full objects
7+
// util.inspect.defaultOptions.depth = 0; // show truncated objects
8+
util.inspect.defaultOptions.compact = true; // dont break objects to new lines
9+
// util.inspect.defaultOptions.compact = false; // break objects to new lines
10+
11+
// suppress jests tracing console logs
12+
import console from 'console';
13+
const jestConsole = console;
14+
import knapsack from './dynamicKnapsack.js';
15+
16+
beforeEach(() => {
17+
global.console = console;
18+
console.log(style.color(255,0,255),'▷',style.reset,style.color(39),expect.getState().currentTestName,style.reset,'\n'); });
19+
20+
afterEach(() => {
21+
global.console = jestConsole;
22+
console.log(style.color(99), style.hr.double, style.reset);
23+
});
24+
25+
describe('dynamicKnapsack', () => {
26+
it('should return optimal value (7 items)', () => {
27+
const weightCap = 50;
28+
const weights = [31, 10, 20, 19, 4, 3, 6];
29+
const values = [70, 20, 39, 37, 7, 5, 10];
30+
expect(knapsack(weightCap, weights, values))
31+
.toBe(107);
32+
});
33+
34+
it('should return optimal value (5 items)', () => {
35+
const weightCap = 5;
36+
const weights = [1, 3, 5];
37+
const values = [250, 300, 500];
38+
expect(knapsack(weightCap, weights, values))
39+
.toBe(550);
40+
});
41+
42+
});
43+

0 commit comments

Comments
 (0)