Problem 9: Special Pythagorean Triplet
View on Project EulerProject Euler Problem 9 Solution
EulerSolve provides an optimized solution for Project Euler Problem 9, Special Pythagorean Triplet, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary A Pythagorean triplet is a triple of positive integers \((a,b,c)\) satisfying $a^2+b^2=c^2.$ In this problem we also impose the fixed-perimeter condition $a+b+c=S,$ with the sides ordered as \(a \lt b \lt c\). The Project Euler target is \(S=1000\), but the implementations are slightly more general: for any positive perimeter \(S\), they search for an ordered triple and return the corresponding product \(abc\), or \(0\) when no such triple exists. Mathematical Approach The core simplification is that the perimeter condition removes one degree of freedom. Once \(a\) and \(b\) are chosen, the hypotenuse is no longer independent, so the search is really over a constrained region in the \((a,b)\)-plane rather than over arbitrary triples. Eliminating the Hypotenuse From the fixed sum we immediately have $c=S-a-b.$ Substitute this into the Pythagorean equation: $a^2+b^2=(S-a-b)^2.$ Expanding and cancelling \(a^2+b^2\) gives $0=S^2-2S(a+b)+2ab.$ Collecting the terms that contain \(b\), $2b(S-a)=S(S-2a),$ so any valid triple must satisfy $\boxed{b=\frac{S(S-2a)}{2(S-a)}}.$ This identity is useful for two reasons. First, for each fixed \(a\) there is at most one possible value of \(b\). Second, a candidate value of \(a\) works only when the denominator \(2(S-a)\) divides the numerator \(S(S-2a)\)....
Detailed mathematical approach
Problem Summary
A Pythagorean triplet is a triple of positive integers \((a,b,c)\) satisfying
$a^2+b^2=c^2.$
In this problem we also impose the fixed-perimeter condition
$a+b+c=S,$
with the sides ordered as \(a \lt b \lt c\). The Project Euler target is \(S=1000\), but the implementations are slightly more general: for any positive perimeter \(S\), they search for an ordered triple and return the corresponding product \(abc\), or \(0\) when no such triple exists.
Mathematical Approach
The core simplification is that the perimeter condition removes one degree of freedom. Once \(a\) and \(b\) are chosen, the hypotenuse is no longer independent, so the search is really over a constrained region in the \((a,b)\)-plane rather than over arbitrary triples.
Eliminating the Hypotenuse
From the fixed sum we immediately have
$c=S-a-b.$
Substitute this into the Pythagorean equation:
$a^2+b^2=(S-a-b)^2.$
Expanding and cancelling \(a^2+b^2\) gives
$0=S^2-2S(a+b)+2ab.$
Collecting the terms that contain \(b\),
$2b(S-a)=S(S-2a),$
so any valid triple must satisfy
$\boxed{b=\frac{S(S-2a)}{2(S-a)}}.$
This identity is useful for two reasons. First, for each fixed \(a\) there is at most one possible value of \(b\). Second, a candidate value of \(a\) works only when the denominator \(2(S-a)\) divides the numerator \(S(S-2a)\). The implementations do not use this closed form directly, but it explains why the brute-force search is so tightly constrained.
Order Constraints Shrink the Search Region
The inequalities \(a \lt b \lt c\) combine with \(a+b+c=S\) to produce immediate bounds.
Because \(a\) is the smallest side, we must have
$3a \lt a+b+c=S,$
hence
$a \lt \frac{S}{3}.$
Likewise, since \(b \lt c=S-a-b\), we get
$2b \lt S-a,$
or equivalently
$b \lt \frac{S-a}{2}.$
These bounds are exactly what make the direct enumeration practical. The implementation scans \(a\) upward, then scans \(b\) starting at \(a+1\), and it discards any pair for which \(c=S-a-b\) has already dropped to \(b\) or below. Once that happens, the order \(a \lt b \lt c\) is impossible for that pair.
Parity and Euclid's Parametrization
There is also a classical number-theoretic description of all integer right triangles. Every Pythagorean triple can be written in the form
$\{a,b\}=\{k(m^2-n^2),\,2kmn\}, \qquad c=k(m^2+n^2),$
with integers \(m \gt n \gt 0\) and \(k \ge 1\). Therefore the perimeter is always
$S=2km(m+n).$
This immediately implies that every admissible perimeter is even. So an odd value of \(S\) can never work. The implementations do not special-case odd inputs, but the formula explains in advance why such searches would end with no solution.
For the Euler target \(S=1000\), the perimeter equation becomes
$500=km(m+n).$
One successful choice is \(m=4\), \(n=1\), \(k=25\). Then the two legs are \(25(4^2-1^2)=375\) and \(25(2\cdot4\cdot1)=200\), while the hypotenuse is \(25(4^2+1^2)=425\). After ordering the two legs, the triple is
$\boxed{(200,375,425)},$
and its product is
$\boxed{200 \cdot 375 \cdot 425 = 31{,}875{,}000.}$
Worked Examples
The small checkpoint case is \(S=12\). The familiar triple \((3,4,5)\) works because
$3^2+4^2=9+16=25=5^2, \qquad 3+4+5=12.$
The product is therefore \(60\), which is why the implementations use this perimeter as a validation case before evaluating the main target.
The derivation above also shows a more structural viewpoint: once \(a\) is chosen, \(b\) is forced by the rational formula, and then \(c\) is forced by the perimeter. So the mathematical problem has only one real free variable, even though the code keeps the simpler two-loop enumeration.
How the Code Works
The C++, Python, and Java implementations all use the same strategy. They iterate through candidate values of \(a\) from \(1\) upward. For each such \(a\), they iterate through candidate values of \(b\) starting from \(a+1\), so the inequality \(a \lt b\) is built directly into the loop structure.
For each pair \((a,b)\), the implementation computes
$c=S-a-b.$
If \(c \le b\), the order \(a \lt b \lt c\) has already failed, so that pair is skipped immediately. Otherwise the code checks the single remaining invariant
$a^2+b^2=c^2.$
As soon as that equation holds, the implementation returns the product \(abc\). For the Project Euler perimeter this is enough, because the ordered solution is unique. If the loops finish without finding a valid triple, the return value is \(0\).
Before handling the main perimeter, the implementations also verify themselves on the sample perimeter \(12\), where the correct product is \(60\). That small check confirms that the arithmetic, the ordering logic, and the return value convention are all consistent.
Complexity Analysis
The nested search examines \(O(S^2)\) candidate pairs \((a,b)\) in the worst case. Each candidate requires only constant-time arithmetic: one subtraction to form \(c\), a comparison for the order test, and a fixed number of multiplications and additions for the Pythagorean check. The running time is therefore \(O(S^2)\).
The memory usage is \(O(1)\), because the implementation stores only a handful of integers regardless of the perimeter. For the Euler target \(S=1000\), this straightforward approach is already comfortably fast.
The closed-form relation for \(b\) shows that one could reduce the search to \(O(S)\) by scanning only over \(a\) and testing divisibility. The given implementations deliberately prefer the simpler double loop, which keeps the code short and still solves the target instance immediately.
Footnotes and References
- Project Euler problem page: https://projecteuler.net/problem=9
- Pythagorean triple: Wikipedia - Pythagorean triple
- Euclid's formula: Wikipedia - Generating a triple
- Further background on integer right triangles: MathWorld - Pythagorean Triple
- Perimeters of integer-sided right triangles: OEIS A024364