From a6f6eb264995c41db646467a0078aa24e4ebec48 Mon Sep 17 00:00:00 2001 From: fpringle Date: Sat, 12 Dec 2020 06:19:35 +0100 Subject: [PATCH] Add solution for Project Euler problem 86 (#4025) * Added solution for Project Euler problem 86 * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> --- DIRECTORY.md | 2 + project_euler/problem_086/__init__.py | 0 project_euler/problem_086/sol1.py | 105 ++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 project_euler/problem_086/__init__.py create mode 100644 project_euler/problem_086/sol1.py diff --git a/DIRECTORY.md b/DIRECTORY.md index cb582e793..7eec7e081 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -729,6 +729,8 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_081/sol1.py) * Problem 085 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_085/sol1.py) + * Problem 086 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_086/sol1.py) * Problem 087 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_087/sol1.py) * Problem 089 diff --git a/project_euler/problem_086/__init__.py b/project_euler/problem_086/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/project_euler/problem_086/sol1.py b/project_euler/problem_086/sol1.py new file mode 100644 index 000000000..0bf66e6b5 --- /dev/null +++ b/project_euler/problem_086/sol1.py @@ -0,0 +1,105 @@ +""" +Project Euler Problem 86: https://projecteuler.net/problem=86 + +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. + +Solution: + Label the 3 side-lengths of the cuboid a,b,c such that 1 <= a <= b <= c <= M. + By conceptually "opening up" the cuboid and laying out its faces on a plane, + it can be seen that the shortest distance between 2 opposite corners is + sqrt((a+b)^2 + c^2). This distance is an integer if and only if (a+b),c make up + the first 2 sides of a pythagorean triplet. + + The second useful insight is rather than calculate the number of cuboids + with integral shortest distance for each maximum cuboid side-length M, + we can calculate this number iteratively each time we increase M, as follows. + The set of cuboids satisfying this property with maximum side-length M-1 is a + subset of the cuboids satisfying the property with maximum side-length M + (since any cuboids with side lengths <= M-1 are also <= M). To calculate the + number of cuboids in the larger set (corresponding to M) we need only consider + the cuboids which have at least one side of length M. Since we have ordered the + side lengths a <= b <= c, we can assume that c = M. Then we just need to count + the number of pairs a,b satisfying the conditions: + sqrt((a+b)^2 + M^2) is integer + 1 <= a <= b <= M + + To count the number of pairs (a,b) satisfying these conditions, write d = a+b. + Now we have: + 1 <= a <= b <= M => 2 <= d <= 2*M + we can actually make the second equality strict, + since d = 2*M => d^2 + M^2 = 5M^2 + => shortest distance = M * sqrt(5) + => not integral. + a + b = d => b = d - a + and a <= b + => a <= d/2 + also a <= M + => a <= min(M, d//2) + + a + b = d => a = d - b + and b <= M + => a >= d - M + also a >= 1 + => a >= max(1, d - M) + + So a is in range(max(1, d - M), min(M, d // 2) + 1) + + For a given d, the number of cuboids satisfying the required property with c = M + and a + b = d is the length of this range, which is + min(M, d // 2) + 1 - max(1, d - M). + + In the code below, d is sum_shortest_sides + and M is max_cuboid_size. + + +""" + + +from math import sqrt + + +def solution(limit: int = 1000000) -> int: + """ + Return the least value of M such that there are more than one million cuboids + of side lengths 1 <= a,b,c <= M such that the shortest distance between two + opposite vertices of the cuboid is integral. + >>> solution(100) + 24 + >>> solution(1000) + 72 + >>> solution(2000) + 100 + >>> solution(20000) + 288 + """ + num_cuboids: int = 0 + max_cuboid_size: int = 0 + sum_shortest_sides: int + + while num_cuboids <= limit: + max_cuboid_size += 1 + for sum_shortest_sides in range(2, 2 * max_cuboid_size + 1): + if sqrt(sum_shortest_sides ** 2 + max_cuboid_size ** 2).is_integer(): + num_cuboids += ( + min(max_cuboid_size, sum_shortest_sides // 2) + - max(1, sum_shortest_sides - max_cuboid_size) + + 1 + ) + + return max_cuboid_size + + +if __name__ == "__main__": + print(f"{solution() = }")