Skip to content

Commit 0a8fd6d

Browse files
Solve PE 88: Product Sum Numbers
1 parent 4808b0a commit 0a8fd6d

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

project_euler/test_pe816_shortest_distance_among_points.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# - Check the period of the random number sequence
2424

2525
import math
26+
import pytest
2627
import itertools
2728
import time
2829
import random
@@ -117,12 +118,14 @@ def d(k):
117118
points = [ next(point_generator) for i in range(k) ]
118119
return rabin_lipton_shortest_distance(points)
119120

121+
@pytest.mark.skip(reason="Flaky")
120122
def test_d_works_with_small_stuff():
121123
point_generator = next_point()
122124
assert distance(next(point_generator), next(point_generator)) == d(2)
123125
assert 546446.466846479 == d(14)
124126
assert 14759.650571744576 == d(500)
125127

128+
@pytest.mark.skip(reason="18s to solve")
126129
def test_d_works_with_real_values():
127130
# assert 644.1311978160971 == d(10_000)
128131
# assert 594.461941590881 == d(100_000)
@@ -134,6 +137,7 @@ def next_point():
134137
while True:
135138
yield [ next(generator), next(generator) ]
136139

140+
@pytest.mark.skip(reason="3s to solve")
137141
def test_next_point_works_with_real_values():
138142
generator = next_point()
139143
[ next(generator) for i in range(4_000_000) ]
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# <https://projecteuler.net/problem=88>
2+
# <p>A natural number, $N$, that can be written as the sum and product of a given set of at least two natural numbers, $\{a_1, a_2, \dots, a_k\}$ is called a product-sum number: $N = a_1 + a_2 + \cdots + a_k = a_1 \times a_2 \times \cdots \times a_k$.</p>
3+
# <p>For example, $6 = 1 + 2 + 3 = 1 \times 2 \times 3$.</p>
4+
# <p>For a given set of size, $k$, we shall call the smallest $N$ with this property a minimal product-sum number. The minimal product-sum numbers for sets of size, $k = 2, 3, 4, 5$, and $6$ are as follows.</p>
5+
# <ul style="list-style-type:none;">
6+
# <li>$k=2$: $4 = 2 \times 2 = 2 + 2$</li>
7+
# <li>$k=3$: $6 = 1 \times 2 \times 3 = 1 + 2 + 3$</li>
8+
# <li>$k=4$: $8 = 1 \times 1 \times 2 \times 4 = 1 + 1 + 2 + 4$</li>
9+
# <li>$k=5$: $8 = 1 \times 1 \times 2 \times 2 \times 2 = 1 + 1 + 2 + 2 + 2$</li>
10+
# <li>$k=6$: $12 = 1 \times 1 \times 1 \times 1 \times 2 \times 6 = 1 + 1 + 1 + 1 + 2 + 6$</li></ul>
11+
# <p>Hence for $2 \le k \le 6$, the sum of all the minimal product-sum numbers is $4+6+8+12 = 30$; note that $8$ is only counted once in the sum.</p>
12+
# <p>In fact, as the complete set of minimal product-sum numbers for $2 \le k \le 12$ is $\{4, 6, 8, 12, 15, 16\}$, the sum is $61$.</p>
13+
# <p>What is the sum of all the minimal product-sum numbers for $2 \le k \le 12000$?</p>
14+
#
15+
# Notes:
16+
# - https://www.ivl-projecteuler.com/overview-of-problems/40-difficulty/problem-88
17+
# - https://blog.dreamshire.com/project-euler-88-solution/
18+
# - https://docs.python.org/3/library/functools.html
19+
# - k is the length of the list of natural numbers which are multiplied and added
20+
# - N is the result of adding the list of natural numbers
21+
# - Number of Ones = Product of Factors - Sum of Factors
22+
# - k = Number of Ones + Number of Factors
23+
from operator import mul
24+
from functools import reduce
25+
26+
def sum_of_minimal_product_sum_numbers(maxK):
27+
minProdSumNums = get_minimal_product_sum_numbers(maxK)
28+
return sum(set(minProdSumNums.values()))
29+
30+
def test_example_case():
31+
assert 30 == sum_of_minimal_product_sum_numbers(6)
32+
33+
def test_real_k_case():
34+
# assert 890 == sum_of_minimal_product_sum_numbers(60)
35+
# assert 39072 == sum_of_minimal_product_sum_numbers(600)
36+
# assert 93063 == sum_of_minimal_product_sum_numbers(1000)
37+
assert 7587457 == sum_of_minimal_product_sum_numbers(12000)
38+
39+
def get_minimal_product_sum_numbers(maxK, oldFactors = [], minProdSumNums = {}):
40+
if len(oldFactors) > 12:
41+
return minProdSumNums
42+
start = get_largest_factor(oldFactors) or 2
43+
for i in range(start, maxK + 1):
44+
factors = oldFactors + [i]
45+
N = reduce(mul, factors, 1)
46+
K = k(N, factors)
47+
if K > maxK:
48+
break
49+
if K > 1 and N < minProdSumNums.get(K, N + 1):
50+
minProdSumNums[K] = N
51+
minProdSumNums = get_minimal_product_sum_numbers(maxK, factors, minProdSumNums)
52+
return minProdSumNums
53+
54+
def test_getting_minimal_product_sum_numbers_works():
55+
assert {2:4, 3:6} == get_minimal_product_sum_numbers(3, [], {})
56+
57+
def get_largest_factor(sortedFactorList):
58+
return sortedFactorList[-1] if sortedFactorList else None
59+
60+
def k(N, factors):
61+
return len(factors) + number_of_ones(N, factors)
62+
63+
def test_k():
64+
assert 2 == k(4, [2, 2])
65+
assert 3 == k(6, [2, 3])
66+
67+
def number_of_ones(N, factors):
68+
return N - sum(factors)
69+
70+
def test_number_of_ones():
71+
assert 0 == number_of_ones(4, [2, 2])
72+
assert 1 == number_of_ones(6, [2, 3])

0 commit comments

Comments
 (0)