Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 94: Almost Equilateral Triangles

View on Project Euler

Project Euler Problem 94 Solution

EulerSolve provides an optimized solution for Project Euler Problem 94, Almost Equilateral Triangles, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary An almost equilateral triangle has integer side lengths of the form \((a,a,a\pm1)\). The task is to sum the perimeters of all such triangles whose area is also an integer and whose perimeter does not exceed \(10^9\). A direct search over all possible side lengths would be wasteful, because the bound is enormous. The key observation used by the implementations is that the integer-area condition can be rewritten as a Pell equation, and that Pell equation has a simple recurrence that generates every valid triangle in increasing order. Mathematical Approach Write the third side as \(a+s\), where \(s\in\{-1,+1\}\). The two cases \(s=+1\) and \(s=-1\) correspond to the triangles \((a,a,a+1)\) and \((a,a,a-1)\). The Altitude Is the Decisive Quantity Drop the altitude from the apex onto the side \(a+s\), and call that altitude \(h\). Because the triangle is isosceles, the altitude bisects the base, so Pythagoras gives $h^2=a^2-\left(\frac{a+s}{2}\right)^2=\frac{3a^2-2sa-1}{4}.$ The area is then $A=\frac{a+s}{2}\,h.$ So the geometric problem is equivalent to finding those values of \(a\) for which the expression on the right produces an integer altitude and therefore an integer area. For this problem, everything reduces to understanding the arithmetic of that altitude....

Detailed mathematical approach

Problem Summary

An almost equilateral triangle has integer side lengths of the form \((a,a,a\pm1)\). The task is to sum the perimeters of all such triangles whose area is also an integer and whose perimeter does not exceed \(10^9\).

A direct search over all possible side lengths would be wasteful, because the bound is enormous. The key observation used by the implementations is that the integer-area condition can be rewritten as a Pell equation, and that Pell equation has a simple recurrence that generates every valid triangle in increasing order.

Mathematical Approach

Write the third side as \(a+s\), where \(s\in\{-1,+1\}\). The two cases \(s=+1\) and \(s=-1\) correspond to the triangles \((a,a,a+1)\) and \((a,a,a-1)\).

The Altitude Is the Decisive Quantity

Drop the altitude from the apex onto the side \(a+s\), and call that altitude \(h\). Because the triangle is isosceles, the altitude bisects the base, so Pythagoras gives

$h^2=a^2-\left(\frac{a+s}{2}\right)^2=\frac{3a^2-2sa-1}{4}.$

The area is then

$A=\frac{a+s}{2}\,h.$

So the geometric problem is equivalent to finding those values of \(a\) for which the expression on the right produces an integer altitude and therefore an integer area. For this problem, everything reduces to understanding the arithmetic of that altitude.

Turning the Area Condition into a Pell Equation

Starting from the formula above, multiply by 12 and rearrange:

$12h^2=9a^2-6sa-3,$

$12h^2+4=9a^2-6sa+1=(3a-s)^2.$

Therefore

$\left(\frac{3a-s}{2}\right)^2-3h^2=1.$

If we define

$x=\frac{3a-s}{2},\qquad y=h,$

then every valid almost equilateral triangle gives a positive integer solution of

$x^2-3y^2=1.$

This Pell equation is the central mathematical object in the solution. Instead of testing side lengths directly, the implementations iterate through Pell solutions and reconstruct the corresponding triangles.

Recovering the Triangle from a Pell State

The reduction is reversible. Given a positive solution \((x,y)\) of \(x^2-3y^2=1\), try \(s=+1\) and \(s=-1\) in

$a=\frac{2x+s}{3},\qquad P=3a+s.$

If \(a\) is an integer greater than 1, then \((a,a,a+s)\) is a non-degenerate almost equilateral triangle with altitude exactly \(y\). Its area is

$A=\frac{a+s}{2}\,y.$

For each Pell state, at most one sign works. That is exactly what the code checks: it tries both branches and keeps only the one for which \((2x+s)\) is divisible by 3 and produces a positive side length. The two families alternate, giving a long-base triangle, then a short-base triangle, then long-base again, and so on.

Why One Recurrence Generates Every Solution

The Pell equation \(x^2-3y^2=1\) has fundamental positive solution \(2+\sqrt{3}\). All positive solutions are generated by powers of this unit:

$x_n+y_n\sqrt{3}=(2+\sqrt{3})^n.$

Multiplying a solution by \(2+\sqrt{3}\) gives the recurrence used verbatim in the implementations:

$x_{n+1}=2x_n+3y_n,\qquad y_{n+1}=x_n+2y_n,$

starting from \((x_1,y_1)=(2,1)\).

The Pell invariant is preserved exactly, because

$\bigl(2x+3y\bigr)^2-3\bigl(x+2y\bigr)^2=x^2-3y^2.$

The initial state \((2,1)\) only leads to the degenerate short-base candidate \(a=1\), so the first real triangle appears one step later. After that, both \(x\) and \(y\) grow exponentially, so the valid triangles are produced in strictly increasing size.

Worked Example: The First Four Valid Perimeters

After one Pell update, the state becomes \((x,y)=(7,4)\). Here \(2x+1=15\) is divisible by 3, so \(a=5\) and \(s=+1\). This yields the triangle \((5,5,6)\), with altitude \(4\), area \(12\), and perimeter \(16\).

The next state is \((26,15)\). Now \(2x-1=51\) is divisible by 3, so \(a=17\) and \(s=-1\). That gives \((17,17,16)\), with altitude \(15\), area \(120\), and perimeter \(50\).

Continuing the same recurrence produces \((65,65,66)\) with perimeter \(196\), then \((241,241,240)\) with perimeter \(722\). Therefore the total perimeter below \(1000\) is

$16+50+196+722=984,$

which is a useful checkpoint for the method.

How the Code Works

The C++, Python, and Java implementations use exactly the Pell formulation above. They never iterate over all possible side lengths and they never perform repeated square-root tests.

The State Carried Through the Loop

The loop stores only two integers, the current Pell solution \((x,y)\). They are initialized to the smallest positive solution \((2,1)\), and each iteration advances to the next solution using

$x\leftarrow 2x+3y,\qquad y\leftarrow x+2y$

with the old values on the right-hand side. This keeps the computation entirely in integer arithmetic.

Converting Each Pell State into a Triangle

For every state, the implementation checks both \(s=+1\) and \(s=-1\). It computes \(a=(2x+s)/3\), discards the branch unless \(a\) is an integer greater than 1, then forms the perimeter \(P=3a+s\). If \(P\le 10^9\), that perimeter is added to the running sum.

Because exactly one branch can succeed for each nontrivial Pell state, each iteration contributes at most one triangle. The altitude is already encoded in \(y\), so no extra geometric verification is needed.

Why Termination Is Safe

The Pell solutions grow roughly by a factor of \(2+\sqrt{3}\approx 3.732\) at each step. Once an iteration produces no admissible perimeter and the current state has already grown past the smallest possible future candidate, every later state is larger as well. That monotonic growth is why the search ends after only a handful of iterations.

Complexity Analysis

Each loop iteration uses only a constant amount of integer arithmetic, so the time per iteration is \(O(1)\). The number of iterations is \(O(\log L)\) for perimeter bound \(L\), because Pell solutions grow exponentially.

For \(L=10^9\), the recurrence produces only 14 valid triangles before the bound is exceeded. Memory usage is \(O(1)\), since the implementation stores only the current Pell state and the running perimeter sum.

Footnotes and References

  1. Problem page: Project Euler 94
  2. Pell equation: Wikipedia - Pell's equation
  3. Heronian triangles: Wikipedia - Heronian triangle
  4. Continued fractions and quadratic irrationals: Wikipedia - Continued fraction

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 93 · All Project Euler solutions · Next: Problem 95

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮