src/knapsackGreedy.js
- import assert from 'assert';
- import {map} from '@iterable-iterator/map';
- import {range} from '@iterable-iterator/range';
- import {sorted} from '@iterable-iterator/sorted';
- import {filter} from '@iterable-iterator/filter';
-
- import Item from './Item.js';
- import orderedByDecreasingUtility from './orderedByDecreasingUtility.js';
-
- /**
- * 1/2-approximation to the 0-1 knapsack problem.
- * Runs in O(n log n) time.
- *
- * Let OPT' be the value of the LP relaxation.
- * Let v_i be the values of the items ordered by utility.
- * Let k be the largest k such that sum(v[:k]) <= W.
- * Let t = (W-sum(w[:k])) / w_{k+1},
- * we have t < 1 and OPT' = sum(v[:k]) + t * v_{k+1}.
- * Hence sum(v[:k+1]) > OPT' >= OPT.
- * By partition one of { sum(v[:k]) , v_{k+1} } is at least OPT / 2.
- * Assuming w_i <= W for all i in [N] each of these is feasible.
- *
- * @param {Array} v Values.
- * @param {Array} w Weights.
- * @param {Number} n Size of the problem.
- * @param {Number} W Size of the knapsack.
- * @return {Number} Lower bound on the objective value of a solution, that is
- * at least half the objective value of the optimum.
- */
- const knapsackGreedy = (v, w, n, W) => {
- assert(v.length === n);
- assert(w.length === n);
- assert(W >= 0);
-
- const items = sorted(
- orderedByDecreasingUtility,
- filter(
- (item) => item.w <= W,
- map((i) => new Item(w[i], v[i]), range(n)),
- ),
- );
- return subroutine(W, items);
- };
-
- const subroutine = (W, items) => {
- let value = 0;
- let capacity = W;
- for (const {v, w} of items) {
- if (capacity < w) return Math.max(v, value);
- capacity -= w;
- value += v;
- }
-
- return value;
- };
-
- export default knapsackGreedy;