From ce8b152bd7c42fa0a8ac9651c75aaa5f8d2cda5d Mon Sep 17 00:00:00 2001
From: Daniele Fucini <dfucini@gmail.com>
Date: Wed, 7 Jun 2023 23:02:57 +0200
Subject: [PATCH] Add python solution for problems 85, 86, 87, 92, 95

---
 Python/p085.py         | 33 +++++++++++++++++++
 Python/p086.py         | 39 ++++++++++++++++++++++
 Python/p087.py         | 44 +++++++++++++++++++++++++
 Python/p092.py         | 57 ++++++++++++++++++++++++++++++++
 Python/p095.py         | 75 ++++++++++++++++++++++++++++++++++++++++++
 Python/projecteuler.py |  3 +-
 README.md              |  4 +--
 7 files changed, 252 insertions(+), 3 deletions(-)
 create mode 100644 Python/p085.py
 create mode 100644 Python/p086.py
 create mode 100644 Python/p087.py
 create mode 100644 Python/p092.py
 create mode 100644 Python/p095.py

diff --git a/Python/p085.py b/Python/p085.py
new file mode 100644
index 0000000..818102e
--- /dev/null
+++ b/Python/p085.py
@@ -0,0 +1,33 @@
+# By counting carefully it can be seen that a rectangular grid measuring 3 by 2 contains eighteen rectangles.
+# Although there exists no rectangular grid that contains exactly two million rectangles, find the area of the grid with the nearest solution.
+
+import sys
+
+from projecteuler import timing
+
+
+@timing
+def p085():
+    N = 2000000
+    min_diff = sys.maxsize
+
+    for i in range(1, 100):
+        for j in range(1, i + 1):
+            # In a 2x3 grid, we can take rectangles of height 2 in 3 ways (two rectangles of heigh
+            # one and one of height 2). For the width, we can take 6 rectangles (3 of width 1,
+            # 2 of width 2 and 1 of width 3). The total is 6x3=18 rectangles.
+            # Extending to m x n, we can take (m+m-1+m-2+...+1)x(n+n-1+n-2+...+1)=
+            # m(m + 1) / 2 * n(n + 1) / 2 = m(m + 1) * n(n + 1) / 4 rectangles
+            n = (i * (i + 1) * j * (j + 1)) / 4
+            diff = abs(N - n)
+
+            if diff < min_diff:
+                min_diff = diff
+                area = i * j
+
+    print('Project Euler, Problem 85')
+    print(f'Answer: {area}')
+
+
+if __name__ == '__main__':
+    p085()
diff --git a/Python/p086.py b/Python/p086.py
new file mode 100644
index 0000000..1f42757
--- /dev/null
+++ b/Python/p086.py
@@ -0,0 +1,39 @@
+# A spider, S, sits in one corner of a cuboid room, measuring 6 by 5 by 3, and a fly, F, sits in the opposite corner.
+# By travelling on the surfaces of the room the shortest "straight line" distance from S to F is 10 and the path is shown on the diagram.
+#
+# However, there are up to three "shortest" path candidates for any given cuboid and the shortest route doesn't always have integer length.
+#
+# It can be shown that there are exactly 2060 distinct cuboids, ignoring rotations, with integer dimensions,
+# up to a maximum size of M by M by M, for which the shortest route has integer length when M = 100.
+# This is the least value of M for which the number of solutions first exceeds two thousand; the number of solutions when M = 99 is 1975.
+#
+# Find the least value of M such that the number of solutions first exceeds one million.
+
+from math import sqrt
+
+from projecteuler import timing
+
+
+@timing
+def p086():
+    N = 1000000
+
+    a = 0
+    count = 0
+
+    while count <= N:
+        a += 1
+
+        for b in range(1, a + 1):
+            for c in range(1, b + 1):
+                d = sqrt(a * a + (b + c) ** 2)
+
+                if d == int(d):
+                    count += 1
+
+    print('Project Euler, Problem 86')
+    print(f'Answer: {a}')
+
+
+if __name__ == '__main__':
+    p086()
diff --git a/Python/p087.py b/Python/p087.py
new file mode 100644
index 0000000..909f608
--- /dev/null
+++ b/Python/p087.py
@@ -0,0 +1,44 @@
+# The smallest number expressible as the sum of a prime square, prime cube, and prime fourth power is 28. In fact,
+# there are exactly four numbers below fifty that can be expressed in such a way:
+#
+# 28 = 22 + 23 + 24
+# 33 = 32 + 23 + 24
+# 49 = 52 + 23 + 24
+# 47 = 22 + 33 + 24
+#
+# How many numbers below fifty million can be expressed as the sum of a prime square, prime cube, and prime fourth power?
+
+from numpy import zeros
+
+from projecteuler import sieve, timing
+
+
+@timing
+def p087():
+    N = 50000000
+    SQRT_N = 7071
+    RAD3_N = 368
+    RAD4_N = 84
+
+    primes = sieve(SQRT_N + 1)
+    numbers = zeros(N)
+    count = 0
+
+    for i in range(2, SQRT_N + 1):
+        if primes[i]:
+            for j in range(2, RAD3_N + 1):
+                if primes[j]:
+                    for k in range(2, RAD4_N + 1):
+                        if primes[k]:
+                            n = i ** 2 + j ** 3 + k ** 4
+
+                            if n < N and numbers[n] == 0:
+                                count += 1
+                                numbers[n] = 1
+
+    print('Project Euler, Problem 87')
+    print(f'Answer: {count}')
+
+
+if __name__ == '__main__':
+    p087()
diff --git a/Python/p092.py b/Python/p092.py
new file mode 100644
index 0000000..a4ae457
--- /dev/null
+++ b/Python/p092.py
@@ -0,0 +1,57 @@
+# A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.
+#
+# For example,
+#
+# 44 → 32 → 13 → 10 → 1 → 1
+# 85 → 89 → 145 → 42 → 20 → 4 → 16 → 37 → 58 → 89
+#
+# Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that
+# EVERY starting number will eventually arrive at 1 or 89.
+#
+# How many starting numbers below ten million will arrive at 89?
+
+from numpy import zeros
+
+from projecteuler import timing
+
+
+N = 10000000
+chains = zeros(N)
+
+
+def chain(n):
+    tmp = 0
+
+    if n == 1:
+        return 1
+
+    if n == 89:
+        return 89
+
+    if chains[n] != 0:
+        return chains[n]
+
+    while n > 0:
+        digit = n % 10
+        tmp += digit ** 2
+        n //= 10
+
+    return chain(tmp)
+
+
+@timing
+def p092():
+    count = 0
+
+    for i in range(1, N):
+        chains[i] = chain(i)
+
+        if chains[i] == 89:
+            count += 1
+
+    print('Project Euler, Problem 92')
+    print(f'Answer: {count}')
+
+
+if __name__ == '__main__':
+    p092()
diff --git a/Python/p095.py b/Python/p095.py
new file mode 100644
index 0000000..0dd1de4
--- /dev/null
+++ b/Python/p095.py
@@ -0,0 +1,75 @@
+# The proper divisors of a number are all the divisors excluding the number itself. For example, the proper divisors
+# of 28 are 1, 2, 4, 7, and 14. As the sum of these divisors is equal to 28, we call it a perfect number.
+#
+# Interestingly the sum of the proper divisors of 220 is 284 and the sum of the proper divisors of 284 is 220,
+# forming a chain of two numbers. For this reason, 220 and 284 are called an amicable pair.
+#
+# Perhaps less well known are longer chains. For example, starting with 12496, we form a chain of five numbers:
+#
+# 12496 → 14288 → 15472 → 14536 → 14264 (→ 12496 → ...)
+#
+# Since this chain returns to its starting point, it is called an amicable chain.
+#
+# Find the smallest member of the longest amicable chain with no element exceeding one million.
+
+from numpy import zeros
+
+from projecteuler import sum_of_divisors, timing
+
+
+N = 1000000
+divisors = zeros(N + 1)
+
+
+def sociable_chain(i, chain, l, min_):
+    chain[l] = i
+
+    if i == 1:
+        return -1
+
+    if divisors[i] != 0:
+        n = int(divisors[i])
+    else:
+        n = int(sum_of_divisors(i))
+
+    if n > N:
+        return -1
+
+    if n == chain[0]:
+        return l + 1
+
+    for j in range(l, 0, -1):
+        if n == chain[j]:
+            return -1
+
+    if n < min_:
+        min_ = n
+
+    return sociable_chain(n, chain, l + 1, min_)
+
+
+@timing
+def p095():
+    chain = zeros(N)
+    min_ = 0
+    l_max = 0
+
+    for i in range(4, N + 1):
+        divisors[i] = sum_of_divisors(i)
+
+        if divisors[i] == i:
+            continue
+
+        min_tmp = i
+        length = sociable_chain(i, chain, 0, min_tmp)
+
+        if length > l_max:
+            l_max = length
+            min_ = min_tmp
+
+    print('Project Euler, Problem 95')
+    print(f'Answer: {min_}')
+
+
+if __name__ == '__main__':
+    p095()
diff --git a/Python/projecteuler.py b/Python/projecteuler.py
index e58bfe4..adda8d9 100644
--- a/Python/projecteuler.py
+++ b/Python/projecteuler.py
@@ -146,7 +146,8 @@ def sum_of_divisors(n):
 
     for i in range(2, limit):
         if n % i == 0:
-            sum_ = sum_ + i
+            sum_ += i
+
             # If n is a perfect square, i=limit is a divisor and has to be counted only once.
             if n != i * i:
                 sum_ = sum_ + n // i
diff --git a/README.md b/README.md
index bda198c..f326f7f 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,6 @@
 These are my solutions in C and Python, not necessarily the best solutions. I've solved most of the first 100 problems, currently working on cleaning the code and uploading it. I will try to solve more problems in the future.
 
 # Notes
-- Solutions for problems 82 and 145 in Python are really slow.
-- Solutions for problems 84, 85, 86, 87, 89, 92, 95, 96, 97. 99, 102, 112, 124 and 357 have been implemented in C but not in Python.
+- Solutions for problems 82, 86, 95, and 145 in Python are quite slow.
+- Solutions for problems 84, 89, 96, 97. 99, 102, 112, 124 and 357 have been implemented in C but not in Python.
 - Solutions for problems 88, 90 and 91 have been implemented in Python but not in C.