Skip to content

Instantly share code, notes, and snippets.

@edvardm
Created April 1, 2011 20:44
Show Gist options
  • Save edvardm/898826 to your computer and use it in GitHub Desktop.
Save edvardm/898826 to your computer and use it in GitHub Desktop.
module Enumerable
def sum
self.inject(0) {|acc, i| acc+i}
end
end
module Harry
class << self
def price(books)
nslots = 5
raise ArgumentError, "books must contain count of each volume in 5 slots" unless books.size == nslots
if books.sum == 0
return 0
else
# simulate picking topmost book from each slot where there it at least one book
mask = slot_mask(books)
selections = bitmasks(nslots).
map { |m| mask_to_array(nslots, m) }.
select {|s| legal_selections(s, books) }
selections.map do |s|
discounted_price_for_selection(s) + price(extract_selection(books, s))
end.min
end
end
def legal_selections(s, books)
extract_selection(books, s).all? {|i| i >= 0}
end
def mask_to_array(size, mask)
(0...size).map {|i| 1 & (mask >> i)}.reverse
end
# pick at least one book from all books with the constraint that all
# picked books are still unique
def extract_selection(books, selection)
books.zip(selection).map { |orig_count, i| orig_count - i }
end
def slot_mask(books)
m = 0
indexes_with_books(books).each_with_index do |i, idx|
m = m | (2**idx) if i == 1
end
m
end
def indexes_with_books(books)
books.map { |i| i > 0 ? 1 : 0 }
end
def bitmasks(length)
(1..(2**length)-1).to_a
end
def discounted_price_for_selection(selection)
unit_price = 8
discounts = [0, 0, 0.05, 0.10, 0.20, 0.25]
uniq_books = selection.sum
(1-discounts[uniq_books]) * unit_price * uniq_books
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment