Project Euler #44: Pentagonal Numbers
- Python
- Algorithms
- C++
- Math
Pentagonal numbers are generated by the formula, . The first ten pentagonal numbers are:
1, 5, 12, 22, 35, 51, 70, 92, 117, 145, ...
It can be seen that . However, their difference, 70 − 22 = 48, is not pentagonal.
Find the pair of pentagonal numbers, and , for which their sum and difference are pentagonal and D = is minimized; what is the value of ?
The pair we are trying to find is and , and it also has to satisfy the constraint that their sum and differences are also pentagonal. Therefore we can write two equations for the sum and difference respectively, where and are the indices of the resulting pentagonal number:
Let be :
Let be , and the same applies to the difference:
Now that we have a formula for and , we can simply verify if a pair meets the stated requirements by testing if the numerator is divisible by 6(which would therefore make and integers).
However, we can try to determine the in the numerators of our equations.
We know that and are indices of a sequence, so they have to be positive integers.
Let's look at , here, we can say that is some constant added to 1, thus transforming it into . Since is a pentagonal number, which starts at 1, it's certain that , and so . Therefore, is definitely greater than 1.
Back to the numerator:
At this stage, since we know that the numerator has to be positive to make and positive, we can safely eliminate the minus sign and obtain:
Finally, to check if a pair satisfies the condition, we can simply substitute or for the values and see if the numerator is divisible by 6.
def getPairDiff(k, j):
return math.fabs(k * (3 * k - 1) / 2 - j * (3 * j - 1) / 2)
def isValidPair(k, j):
x = k * (3 * k - 1)
y = j * (3 * j - 1)
# calculating the sqrt part
p1 = (1 + 12 * (
abs(x - y)
))**0.5
# slight optimization, avoids further computation in some scenarios
if not p1.is_integer():
return False
p2 = (1 + 12 * (
x + y
))**0.5
# same optimization as the p1 check
if not p2.is_integer():
return False
# check for divisibility
diffIsPentagonal = (1 + p1) % 6 == 0
sumIsPentagonal = (1 + p2) % 6 == 0
# both numerators have to be divisible by 6
return sumIsPentagonal and diffIsPentagonal
def main():
d = None
i = 2
start = time.time()
while not d:
for j in range(1, i):
if isValidPair(i, j):
d = getPairDiff(i, j)
i += 1
end = time.time()
d = int(d)
print(
f"Computed solution: {d}; took {1000*(round(1000 * (end-start)) / 1000)}ms")
#include <iostream>
#include <cmath>
int getPairDiff(int k, int j)
{
return abs(k * (3 * k - 1) / 2 - j * (3 * j - 1) / 2);
}
bool isValidPair(int k, int j)
{
int x = k * (3 * k - 1);
int y = j * (3 * j - 1);
double t1 = sqrt(1 + 12 * (
abs(x - y)
));
if (trunc(t1) != t1)
{
return false;
}
double t2 = sqrt(1 + 12 * (
x + y
));
if (trunc(t2) != t2)
{
return false;
}
double diff = (1 + t1) / 6;
if (trunc(diff) != diff)
{
return false;
}
double sum = (1 + t2) / 6;
return trunc(sum) == sum;
}
int main() {
int d = 0;
int i = 2;
while (d == 0)
{
for (int j = 1; j < i; ++j)
{
if (isValidPair(i, j))
{
d = getPairDiff(i, j);
break;
}
}
i++;
}
printf("Computed solution: %d", d);
}
I implemented the algorithm in C++ because with Python the execution time was hideous. However, in C++, it's much faster.
Average run times:
$ time ./main
Computed solution: 5482660
real 0m0.017s
user 0m0.017s
sys 0m0.000s
$ python src/main.py
Computed solution: 5482660; took 1746.0ms