knapsack_problem_bounded.sf 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Knapsack_problem/Bounded
  4. #
  5. var raw = <<'TABLE'
  6. map 9 150 1
  7. compass 13 35 1
  8. water 153 200 2
  9. sandwich 50 60 2
  10. glucose 15 60 2
  11. tin 68 45 3
  12. banana 27 60 3
  13. apple 39 40 3
  14. cheese 23 30 1
  15. beer 52 10 1
  16. suntancream 11 70 1
  17. camera 32 30 1
  18. T-shirt 24 15 2
  19. trousers 48 10 2
  20. umbrella 73 40 1
  21. w_trousers 42 70 1
  22. w_overcoat 43 75 1
  23. note-case 22 80 1
  24. sunglasses 7 20 1
  25. towel 18 12 2
  26. socks 4 50 1
  27. book 30 10 2
  28. TABLE
  29. struct KnapsackItem {
  30. String name,
  31. Number weight,
  32. Number value,
  33. Number quant,
  34. }
  35. var items = []
  36. raw.each_line{ |row|
  37. var fields = row.words;
  38. items << KnapsackItem(
  39. name: fields[0],
  40. weight: fields[1].to_n,
  41. value: fields[2].to_n,
  42. quant: fields[3].to_n,
  43. )
  44. }
  45. func pick(weight, pos) is cached {
  46. if (pos.is_neg || weight.is_neg || weight.is_zero) {
  47. return (0, 0, [])
  48. }
  49. var (bv=0, bi=0, bw=0, bp=[])
  50. var item = items[pos];
  51. for i in range(0, item.quant) {
  52. break if (i*item.weight > weight)
  53. var (v, w, p) = pick(weight - i*item.weight, pos.dec)
  54. next if ((v += i*item.value) <= bv)
  55. (bv, bi, bw, bp) = (v, i, w, p)
  56. }
  57. (bv, bw + bi*item.weight, [bp..., bi])
  58. }
  59. var (v, w, p) = pick(400, items.end)
  60. p.range.each { |i|
  61. say "#{p[i]} of #{items[i].name}" if p[i].is_pos
  62. }
  63. say "Value: #{v}; Weight: #{w}"