1 | """ |
||
2 | Project Euler Problem 21: Amicable Numbers |
||
3 | ========================================== |
||
4 | |||
5 | .. module:: solutions.problem21 |
||
6 | :synopsis: My solution to problem #21. |
||
7 | |||
8 | The source code for this problem can be |
||
9 | `found here <https://bitbucket.org/nekedome/project-euler/src/master/solutions/problem21.py>`_. |
||
10 | |||
11 | Problem Statement |
||
12 | ################# |
||
13 | |||
14 | Let :math:`d(n)` be defined as the sum of proper divisors of :math:`n` (numbers less than :math:`n` which divide evenly |
||
0 ignored issues
–
show
|
|||
15 | into :math:`n`). |
||
16 | |||
17 | If :math:`d(a) = b` and :math:`d(b) = a`, where :math:`a \\neq b`, then :math:`a` and :math:`b` are an amicable pair and |
||
0 ignored issues
–
show
|
|||
18 | each of :math:`a` and :math:`b` are called amicable numbers. |
||
19 | |||
20 | For example, the proper divisors of :math:`220` are :math:`1, 2, 4, 5, 10, 11, 20, 22, 44, 55` and :math:`110`; |
||
0 ignored issues
–
show
|
|||
21 | therefore :math:`d(220) = 284`. The proper divisors of :math:`284` are :math:`1, 2, 4, 71` and :math:`142`; so |
||
0 ignored issues
–
show
|
|||
22 | :math:`d(284) = 220`. |
||
23 | |||
24 | Evaluate the sum of all the amicable numbers under :math:`10000`. |
||
25 | |||
26 | Solution Discussion |
||
27 | ################### |
||
28 | |||
29 | Pre-compute :math:`d(n)` for all :math:`n` in our search space and then iterate over :math:`n` searching for |
||
0 ignored issues
–
show
|
|||
30 | :math:`d(n) = m` and :math:`d(m) = n` where :math:`n \\neq m`. Compute the sum of all such :math:`(n, m)`. |
||
0 ignored issues
–
show
|
|||
31 | |||
32 | .. note:: the pre-computation of :math:`d(n)` for an increasing :math:`n` can be drastically sped up by using sieving |
||
0 ignored issues
–
show
|
|||
33 | techniques. An alternative, but inferior, method would be to find the divisors of increasing values of |
||
0 ignored issues
–
show
|
|||
34 | :math:`n` via factorisation. |
||
35 | |||
36 | Solution Implementation |
||
37 | ####################### |
||
38 | |||
39 | .. literalinclude:: ../../solutions/problem21.py |
||
40 | :language: python |
||
41 | :lines: 44- |
||
42 | """ |
||
43 | |||
44 | from lib.numbertheory.sieve import divisors_sieve |
||
45 | |||
46 | |||
47 | def solve(): |
||
48 | """ Compute the answer to Project Euler's problem #21 """ |
||
49 | |||
50 | # Pre-compute d(n) for all n in [2, 9999] |
||
51 | target = 10000 |
||
52 | divisor_counts = divisors_sieve(target - 1, proper=True, aggregate="sum") |
||
53 | d_vals = {n + 1: div_count for n, div_count in enumerate(divisor_counts)} |
||
54 | del d_vals[1] # divisors_sieve covers the closed interval [1, target - 1], remove d(1) |
||
55 | |||
56 | # Identify amicable numbers |
||
57 | amicable_numbers = set() |
||
58 | for n, d_n in d_vals.items(): |
||
0 ignored issues
–
show
The name
n 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. ![]() |
|||
59 | if d_n in d_vals and d_vals[d_n] == n and n != d_n: |
||
60 | amicable_numbers.add(n) |
||
61 | amicable_numbers.add(d_n) |
||
62 | |||
63 | # Sum all amicable numbers |
||
64 | answer = sum(amicable_numbers) |
||
65 | return answer |
||
66 | |||
67 | |||
68 | expected_answer = 31626 |
||
0 ignored issues
–
show
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. ![]() |
|||
69 |
This check looks for lines that are too long. You can specify the maximum line length.