Skip to content

Commit 4059171

Browse files
✨ feat(knapsackUnboundedGreedy): First draft.
Progress towards #3.
1 parent c225f94 commit 4059171

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import integerValuesKnapsackUnbounded from './integerValuesKnapsackUnbounded';
33
import integerWeightsKnapsack from './integerWeightsKnapsack';
44
import integerWeightsKnapsackUnbounded from './integerWeightsKnapsackUnbounded';
55
import knapsackApprox from './knapsackApprox';
6+
import knapsackUnboundedGreedy from './knapsackUnboundedGreedy';
67

78
/* eslint import/no-anonymous-default-export: [2, {"allowObject": true}] */
89
export default {
@@ -11,6 +12,7 @@ export default {
1112
integerWeightsKnapsack,
1213
integerWeightsKnapsackUnbounded,
1314
knapsackApprox,
15+
knapsackUnboundedGreedy,
1416
};
1517

1618
export {
@@ -19,4 +21,5 @@ export {
1921
integerWeightsKnapsack,
2022
integerWeightsKnapsackUnbounded,
2123
knapsackApprox,
24+
knapsackUnboundedGreedy,
2225
};

src/knapsackUnboundedGreedy.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import assert from 'assert';
2+
import {fn, decreasing} from '@aureooms/js-compare';
3+
import {map, range, sorted} from '@aureooms/js-itertools';
4+
5+
/**
6+
* 1/2-approximation to the unbounded knapsack problem.
7+
* Runs in O(n log n) time.
8+
*
9+
* @param {Array} v Values.
10+
* @param {Array} w Weights.
11+
* @param {Number} n Size of the problem.
12+
* @param {Number} W Size of the knapsack.
13+
*/
14+
const knapsackUnboundedGreedy = (v, w, n, W) => {
15+
assert(v.length === n);
16+
assert(w.length === n);
17+
assert(W >= 0);
18+
19+
const items = sorted(
20+
orderedByDecreasingUtility,
21+
map((i) => new Item(w[i], v[i]), range(n)),
22+
);
23+
return subroutine(W, items);
24+
};
25+
26+
const subroutine = (W, items) => {
27+
let value = 0;
28+
let capacity = W;
29+
for (const {v, w} of items) {
30+
const copies = Math.floor(capacity / w);
31+
capacity -= copies * w;
32+
value += copies * v;
33+
}
34+
35+
return value;
36+
};
37+
38+
function Item(weight, value) {
39+
assert(weight > 0);
40+
this.w = weight;
41+
this.v = value;
42+
}
43+
44+
const utility = (x) => x.v / x.w;
45+
const orderedByDecreasingUtility = fn(decreasing, utility);
46+
47+
export default knapsackUnboundedGreedy;

test/src/unbounded-knapsack-problem.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {all, map} from '@aureooms/js-itertools';
55
import {
66
integerValuesKnapsackUnbounded,
77
integerWeightsKnapsackUnbounded,
8+
knapsackUnboundedGreedy,
89
} from '../../src';
910

1011
const macro = (t, solve, _name, v, w, n, W, opt, approx) => {
@@ -38,6 +39,10 @@ const solvers = [
3839
solve: integerWeightsKnapsackUnbounded,
3940
hypothesis: (_, w) => all(map((x) => Number.isInteger(x), w)),
4041
},
42+
{
43+
solve: knapsackUnboundedGreedy,
44+
approx: 1 / 2,
45+
},
4146
];
4247

4348
const instances = [

0 commit comments

Comments
 (0)