Skip to content

Commit 6f2e9b3

Browse files
✨ feat(knapsackGreedy): First draft.
Fixes #3.
1 parent d860624 commit 6f2e9b3

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import integerValuesKnapsackUnbounded from './integerValuesKnapsackUnbounded';
44
import integerWeightsKnapsack from './integerWeightsKnapsack';
55
import integerWeightsKnapsackUnbounded from './integerWeightsKnapsackUnbounded';
66
import knapsackApprox from './knapsackApprox';
7+
import knapsackGreedy from './knapsackGreedy';
78
import knapsackUnboundedGreedy from './knapsackUnboundedGreedy';
89
import orderedByDecreasingUtility from './orderedByDecreasingUtility';
910

@@ -15,6 +16,7 @@ export default {
1516
integerWeightsKnapsack,
1617
integerWeightsKnapsackUnbounded,
1718
knapsackApprox,
19+
knapsackGreedy,
1820
knapsackUnboundedGreedy,
1921
orderedByDecreasingUtility,
2022
};
@@ -26,6 +28,7 @@ export {
2628
integerWeightsKnapsack,
2729
integerWeightsKnapsackUnbounded,
2830
knapsackApprox,
31+
knapsackGreedy,
2932
knapsackUnboundedGreedy,
3033
orderedByDecreasingUtility,
3134
};

src/knapsackGreedy.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import assert from 'assert';
2+
import {map, range, sorted, filter} from '@aureooms/js-itertools';
3+
4+
import Item from './Item';
5+
import orderedByDecreasingUtility from './orderedByDecreasingUtility';
6+
7+
/**
8+
* 1/2-approximation to the 0-1 knapsack problem.
9+
* Runs in O(n log n) time.
10+
*
11+
* Let OPT' be the value of the LP relaxation.
12+
* Let v_i be the values of the items ordered by utility.
13+
* Let k be the largest k such that sum(v[:k]) <= W.
14+
* Let t = (W-sum(w[:k])) / w_{k+1},
15+
* we have t < 1 and OPT' = sum(v[:k]) + t * v_{k+1}.
16+
* Hence sum(v[:k+1]) > OPT' >= OPT.
17+
* By partition one of { sum(v[:k]) , v_{k+1} } is at least OPT / 2.
18+
* Assuming w_i <= W for all i in [N] each of these is feasible.
19+
*
20+
* @param {Array} v Values.
21+
* @param {Array} w Weights.
22+
* @param {Number} n Size of the problem.
23+
* @param {Number} W Size of the knapsack.
24+
*/
25+
const knapsackGreedy = (v, w, n, W) => {
26+
assert(v.length === n);
27+
assert(w.length === n);
28+
assert(W >= 0);
29+
30+
const items = sorted(
31+
orderedByDecreasingUtility,
32+
filter(
33+
(item) => item.w <= W,
34+
map((i) => new Item(w[i], v[i]), range(n)),
35+
),
36+
);
37+
return subroutine(W, items);
38+
};
39+
40+
const subroutine = (W, items) => {
41+
let value = 0;
42+
let capacity = W;
43+
for (const {v, w} of items) {
44+
if (capacity < w) return Math.max(v, value);
45+
capacity -= w;
46+
value += v;
47+
}
48+
49+
return value;
50+
};
51+
52+
export default knapsackGreedy;

test/src/0-1-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
integerValuesKnapsack,
77
integerWeightsKnapsack,
8+
knapsackGreedy,
89
knapsackApprox,
910
} from '../../src';
1011

@@ -52,6 +53,10 @@ const solvers = [
5253
solve: integerWeightsKnapsack,
5354
hypothesis: (_, w) => all(map((x) => Number.isInteger(x), w)),
5455
},
56+
{
57+
solve: knapsackGreedy,
58+
approx: 1 / 2,
59+
},
5560
approx(1 / 2),
5661
approx(2 / 3),
5762
approx(3 / 4),

0 commit comments

Comments
 (0)