|
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 group_cost(group): |
8 | | - return len(group) * discount[len(group)] |
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(group_cost, self.groups)) * BASE_COST |
17 | | - |
18 | | - def dup(self): |
19 | | - return Grouping(list(map(set, self.groups))) |
20 | | - |
21 | | - def add_to_valid(self, book): |
22 | | - """Returns all possible groupings from the |
23 | | - current grouping adding book |
24 | | - """ |
25 | | - other = self.dup() |
26 | | - other.groups.sort(key=lambda g: len(g)) |
27 | | - results = [] |
28 | | - for index, group in enumerate(other.groups): |
29 | | - if book not in group: |
30 | | - other2 = other.dup() |
31 | | - other2.groups[index].add(book) |
32 | | - results.append(other2) |
33 | | - if not results: |
34 | | - other.groups.append(set([book])) |
35 | | - return [other] |
36 | | - return results |
37 | | - |
38 | | - def __lt__(self, other): |
39 | | - return self.total() < other.total() |
40 | | - |
41 | | - |
42 | | -def step(basket, book): |
43 | | - return [group for groupings in basket |
44 | | - for group in groupings.add_to_valid(book)] |
45 | | - |
46 | | - |
47 | | -def total(basket): |
48 | | - if len(basket) == 0: |
| 1 | +from collections import Counter |
| 2 | + |
| 3 | +PER_BOOK = 800.00 |
| 4 | +PER_GROUP = { |
| 5 | + 1: 1 * PER_BOOK * 1.00, |
| 6 | + 2: 2 * PER_BOOK * 0.95, |
| 7 | + 3: 3 * PER_BOOK * 0.90, |
| 8 | + 4: 4 * PER_BOOK * 0.80, |
| 9 | + 5: 5 * PER_BOOK * 0.75, |
| 10 | +} |
| 11 | + |
| 12 | + |
| 13 | +def _total(books): |
| 14 | + volumes = Counter(books) |
| 15 | + price = len(books) * PER_BOOK |
| 16 | + for size in range(len(volumes), 1, -1): |
| 17 | + group = volumes - Counter(k for k, _ in volumes.most_common(size)) |
| 18 | + group_books = sorted(group.elements()) |
| 19 | + price = min(price, PER_GROUP[size] + _total(group_books)) |
| 20 | + return price |
| 21 | + |
| 22 | + |
| 23 | +def total(books): |
| 24 | + if not books: |
49 | 25 | return 0 |
50 | | - start = Grouping([{basket[0]}]) |
51 | | - return round(min(reduce(step, basket[1:], [start])).total()) |
| 26 | + return _total(sorted(books)) |
0 commit comments