|
1 | | -from collections import Counter |
2 | | -BOOK_PRICE = 800 |
3 | | - |
4 | | - |
5 | | -def _group_price(size): |
6 | | - discounts = [0, .05, .1, .2, .25] |
7 | | - if not (0 < size <= 5): |
8 | | - raise ValueError('size must be in 1..' + len(discounts)) |
9 | | - return BOOK_PRICE * size * (1 - discounts[size - 1]) |
10 | | - |
11 | | - |
12 | | -def calculate_total(books, price_so_far=0.): |
13 | | - if not books: |
14 | | - return price_so_far |
15 | | - |
16 | | - reordered_books = [] |
17 | | - groups = [] |
18 | | - for value, count in Counter(books).most_common(): |
19 | | - reordered_books = reordered_books + [value] * count |
20 | | - groups.append(value) |
21 | | - min_price = float('inf') |
22 | | - |
23 | | - for i in range(len(groups)): |
24 | | - |
25 | | - remaining_books = reordered_books[:] |
26 | | - |
27 | | - for v in groups[:i + 1]: |
28 | | - remaining_books.remove(v) |
29 | | - |
30 | | - price = calculate_total(remaining_books, |
31 | | - price_so_far + _group_price(i + 1)) |
32 | | - min_price = min(min_price, price) |
33 | | - |
34 | | - return min_price |
| 1 | +from functools import reduce |
| 2 | + |
| 3 | +BASE_COST = 800 |
| 4 | +discount = [1.0, 1.0, 0.95, 0.9, 0.8, 0.75] |
| 5 | + |
| 6 | + |
| 7 | +def groupCost(g): |
| 8 | + return len(g) * discount[len(g)] |
| 9 | + |
| 10 | + |
| 11 | +class Grouping: |
| 12 | + def __init__(self, groups=None): |
| 13 | + self.groups = [set()] if groups is None else groups |
| 14 | + |
| 15 | + def total(self): |
| 16 | + return sum(map(groupCost, self.groups)) * BASE_COST |
| 17 | + |
| 18 | + def dup(self): |
| 19 | + return Grouping(list(map(set, self.groups))) |
| 20 | + |
| 21 | + def add_to_valid(self, b): |
| 22 | + """Returns all possible groupings from current grouping adding book b |
| 23 | + """ |
| 24 | + other = self.dup() |
| 25 | + other.groups.sort(key=lambda g: len(g)) |
| 26 | + results = [] |
| 27 | + for i, g in enumerate(other.groups): |
| 28 | + if b not in g: |
| 29 | + o2 = other.dup() |
| 30 | + o2.groups[i].add(b) |
| 31 | + results.append(o2) |
| 32 | + if not results: |
| 33 | + other.groups.append(set([b])) |
| 34 | + return [other] |
| 35 | + return results |
| 36 | + |
| 37 | + def __lt__(self, other): |
| 38 | + return self.total() < other.total() |
| 39 | + |
| 40 | + |
| 41 | +def step(rs, b): |
| 42 | + return [g for r in rs for g in r.add_to_valid(b)] |
| 43 | + |
| 44 | + |
| 45 | +def calculate_total(books): |
| 46 | + if len(books) == 0: |
| 47 | + return 0 |
| 48 | + start = Grouping([{books[0]}]) |
| 49 | + return round(min(reduce(step, books[1:], [start])).total()) |
0 commit comments