problem-solving/knapsack Home Manual Reference Source

src/knapsackGreedy.js

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