solutions.problem31.partial_solutions()   A
last analyzed

Complexity

Conditions 5

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nop 2
dl 0
loc 18
rs 9.3333
c 0
b 0
f 0
1
"""
2
Project Euler Problem 31: Coin Sums
3
===================================
4
5
.. module:: solutions.problem31
6
   :synopsis: My solution to problem #31.
7
8
The source code for this problem can be
9
`found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem31.py>`_.
10
11
Problem Statement
12
#################
13
14
In England the currency is made up of pound, :raw-html:`&pound;`, and pence, p, and there are eight coins in general
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (116/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
15
circulation:
16
17
    :math:`1p, 2p, 5p, 10p, 20p, 50p,` :raw-html:`&pound;1` :math:`(100p)` and :raw-html:`&pound;2` :math:`(200p)`.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
18
19
It is possible to make :raw-html:`&pound;2` in the following way:
20
21
    :math:`1 \\times` :raw-html:`&pound;1` :math:`+ 1 \\times 50p + 2 \\times 20p + 1 \\times 5p + 1 \\times 2p +`
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
22
    :math:`3 \\times 1p`
23
24
How many different ways can :raw-html:`&pound;2` be made using any number of coins?
25
26
Solution Discussion
27
###################
28
29
This solution is inspired by a `meet-in-the-middle approach <https://en.wikipedia.org/wiki/Meet-in-the-middle_attack>`_.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (120/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
30
31
We will separate the denominations into three mutually exclusive subsets. Two subsets representing similarly sized
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (114/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
32
subspaces and a final subset consisting of the one pence coin. More specifically:
33
34
* :math:`\\lbrace 2p, 20p, 50p \\rbrace`
35
* :math:`\\lbrace 5p, 10p, 100p, 200p \\rbrace`
36
* :math:`\\lbrace 1p \\rbrace`
37
38
Consider the possible range of coins of a given denomination :math:`x` s.t. the sum-total doesn't exceed
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (104/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
39
:raw-html:`&pound;2`.
40
41
.. math::
42
43
    0 \\le \\# \\mbox{ coins of denomination } x \\le \\left \\lfloor \\frac{200}{x} \\right \\rfloor
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
44
45
These bounds give the size of each search space associated with the denomination :math:`x`.
46
47
The size of the search space associated with each subset is the size of the cross product of the respective
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (107/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
48
denominations. That is:
49
50
* :math:`|| \\lbrace 1p \\rbrace || = (200+1) = 201`
51
* :math:`|| \\lbrace 2p, 20p, 50p \\rbrace || =`
52
  :math:`(100 + 1) \\times (10 + 1) \\times (4 + 1) = 101 \\times 11 \\times 5 = 5555`
53
* :math:`|| \\lbrace 5p, 10p, 100p, 200p \\rbrace || =`
54
  :math:`(40 + 1) \\times (20 + 1) \\times (2 + 1) \\times (1 + 1) = 41 \\times 21 \\times 3 \\times 2 = 5166`
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (110/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
55
56
.. note:: the one pence coin is considered separately for a very specific reason. As long as the total of all other
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
57
          denominations is no greater than two pounds then a solution is possible by adding the required number of one
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (118/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
58
          pence coins until two pounds is achieved.
59
60
Now, the algorithm is simple. Find all combinations of coins from each of the two non-trivial subsets that do not
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
61
exceed two pounds. Search through the cross product of these two spaces and every total combination not exceeding
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
62
two pounds is a valid answer. The difference can simply be padded with one pence coins until two pounds is reached.
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (115/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
63
64
Solution Implementation
65
#######################
66
67
.. literalinclude:: ../../solutions/problem31.py
68
   :language: python
69
   :lines: 72-
70
"""
71
72
from itertools import product
73
from typing import Dict, List
74
75
76
def partial_solutions(bounds: Dict[int, int], threshold: int) -> List[int]:
77
    """ Produce the set of combinations of coins that doesn't exceed `threshold` pence
78
79
    The coins that may be used are specified in `bounds` which is a dictionary mapping denominations to the upper bound
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (119/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
80
    in the search space for that denomination.
81
82
    :param bounds: dictionary mapping denominations to search space upper bounds
83
    :param threshold: the sum-total threshold
84
    :return: the list of totals given by combinations of coins not exceeding `threshold`
85
    """
86
87
    rv = []
0 ignored issues
show
Coding Style Naming introduced by
The name rv does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
88
    for x in product(*(range(bounds[y] + 1) for y in bounds.keys())):
0 ignored issues
show
Coding Style Naming introduced by
The name x does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
89
        subtotal = sum([ai * bi for ai, bi in zip(x, bounds.keys())])
90
        if subtotal <= threshold:
91
            rv.append(subtotal)
92
    rv.sort()
93
    return rv
94
95
96
def solve():
97
    """ Compute the answer to Project Euler's problem #31 """
98
99
    target = 200  # in pence
100
    subset1, subset2 = [2, 20, 50], [5, 10, 100, 200]  # 1p is not included
101
    bounds1 = {pence: target // pence for pence in subset1}
102
    bounds2 = {pence: target // pence for pence in subset2}
103
104
    # Independently compute partial solutions based on each non-trivial subset
105
    partial_solutions1 = partial_solutions(bounds1, target)
106
    partial_solutions2 = partial_solutions(bounds2, target)
107
108
    # Consider the cross-product of partial solutions and identify any combination not exceeding two points
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (107/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
109
    answer = 0
110
    for ps1 in partial_solutions1:
111
        for ps2 in partial_solutions2:
112
            if ps1 + ps2 <= target:
113
                answer += 1  # 1p coins can increase this to target as required
114
            else:
115
                break  # ps1 + ps2 for all further ps2 will now exceed target due to sorting
116
    return answer
117
118
119
expected_answer = 73682
0 ignored issues
show
Coding Style Naming introduced by
The name expected_answer does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
120