TheAlgorithms-Python
108 строк · 4.2 Кб
1"""
2Project Euler Problem 85: https://projecteuler.net/problem=85
3
4By counting carefully it can be seen that a rectangular grid measuring 3 by 2
5contains eighteen rectangles.
6
7Although there exists no rectangular grid that contains exactly two million
8rectangles, find the area of the grid with the nearest solution.
9
10Solution:
11
12For a grid with side-lengths a and b, the number of rectangles contained in the grid
13is [a*(a+1)/2] * [b*(b+1)/2)], which happens to be the product of the a-th and b-th
14triangle numbers. So to find the solution grid (a,b), we need to find the two
15triangle numbers whose product is closest to two million.
16
17Denote these two triangle numbers Ta and Tb. We want their product Ta*Tb to be
18as close as possible to 2m. Assuming that the best solution is fairly close to 2m,
19We can assume that both Ta and Tb are roughly bounded by 2m. Since Ta = a(a+1)/2,
20we can assume that a (and similarly b) are roughly bounded by sqrt(2 * 2m) = 2000.
21Since this is a rough bound, to be on the safe side we add 10%. Therefore we start
22by generating all the triangle numbers Ta for 1 <= a <= 2200. This can be done
23iteratively since the ith triangle number is the sum of 1,2, ... ,i, and so
24T(i) = T(i-1) + i.
25
26We then search this list of triangle numbers for the two that give a product
27closest to our target of two million. Rather than testing every combination of 2
28elements of the list, which would find the result in quadratic time, we can find
29the best pair in linear time.
30
31We iterate through the list of triangle numbers using enumerate() so we have a
32and Ta. Since we want Ta * Tb to be as close as possible to 2m, we know that Tb
33needs to be roughly 2m / Ta. Using the formula Tb = b*(b+1)/2 as well as the
34quadratic formula, we can solve for b:
35b is roughly (-1 + sqrt(1 + 8 * 2m / Ta)) / 2.
36
37Since the closest integers to this estimate will give product closest to 2m,
38we only need to consider the integers above and below. It's then a simple matter
39to get the triangle numbers corresponding to those integers, calculate the product
40Ta * Tb, compare that product to our target 2m, and keep track of the (a,b) pair
41that comes the closest.
42
43
44Reference: https://en.wikipedia.org/wiki/Triangular_number
45https://en.wikipedia.org/wiki/Quadratic_formula
46"""
47
48from __future__ import annotations49
50from math import ceil, floor, sqrt51
52
53def solution(target: int = 2000000) -> int:54"""55Find the area of the grid which contains as close to two million rectangles
56as possible.
57>>> solution(20)
586
59>>> solution(2000)
6072
61>>> solution(2000000000)
6286595
63"""
64triangle_numbers: list[int] = [0]65idx: int66
67for idx in range(1, ceil(sqrt(target * 2) * 1.1)):68triangle_numbers.append(triangle_numbers[-1] + idx)69
70# we want this to be as close as possible to target71best_product: int = 072# the area corresponding to the grid that gives the product closest to target73area: int = 074# an estimate of b, using the quadratic formula75b_estimate: float76# the largest integer less than b_estimate77b_floor: int78# the largest integer less than b_estimate79b_ceil: int80# the triangle number corresponding to b_floor81triangle_b_first_guess: int82# the triangle number corresponding to b_ceil83triangle_b_second_guess: int84
85for idx_a, triangle_a in enumerate(triangle_numbers[1:], 1):86b_estimate = (-1 + sqrt(1 + 8 * target / triangle_a)) / 287b_floor = floor(b_estimate)88b_ceil = ceil(b_estimate)89triangle_b_first_guess = triangle_numbers[b_floor]90triangle_b_second_guess = triangle_numbers[b_ceil]91
92if abs(target - triangle_b_first_guess * triangle_a) < abs(93target - best_product94):95best_product = triangle_b_first_guess * triangle_a96area = idx_a * b_floor97
98if abs(target - triangle_b_second_guess * triangle_a) < abs(99target - best_product100):101best_product = triangle_b_second_guess * triangle_a102area = idx_a * b_ceil103
104return area105
106
107if __name__ == "__main__":108print(f"{solution() = }")109