Almost Right-angled Triangles II
How many ordered triples (a,b,c) with a <= b <= c, a^2+b^2=c^2-1, a+b+c <= 75,000,000 exist?
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Let us call an integer sided triangle with sides \(a \le b \le c\)
\(a^2 + b^2 = c^2 - 1\).
How many barely obtuse triangles are there with perimeter \(\le 75\,000\,000\)?
Problem 224: Almost Right-angled Triangles II
Mathematical Development
Write
We want the positive integer solutions of
Any common divisor of would also divide
so every solution is primitive.
The classical Berggren matrices for the ternary quadratic form are
Each satisfies
so they preserve the equation .
The smallest positive solution is
and the Hall-Berggren theory for this form shows that every positive solution of is obtained by repeatedly applying these matrices.
Because and play symmetric roles, we sort them after each transformation. When , the first and third matrices produce the same sorted child, so only two distinct descendants remain. That gives a duplicate-free tree.
Therefore the counting problem is reduced to a depth-first traversal of that tree, pruning as soon as
Editorial
The direct factorization
is valid, but it is not the most convenient way to count all solutions up to a perimeter of seventy-five million. The better observation is that the equation lives on the quadratic surface
and that this surface has the same Berggren-style tree structure that ordinary Pythagorean triples have.
So instead of factoring for millions of values of , we start from the root and generate every solution exactly once. Each matrix application gives a new valid triple, sorting the first two coordinates restores the convention , and the perimeter bound cuts off the recursion naturally. That turns the problem into a pure tree walk with almost no arithmetic overhead.
Pseudocode
Store the three Berggren matrices that preserve a^2 + b^2 - c^2.
Initialize a stack with the root triple (2, 2, 3).
Set the answer counter to 0.
While the stack is not empty:
remove one triple (a, b, c)
reorder the first two entries so that a <= b
If a + b + c exceeds the perimeter limit:
discard this branch
continue
Count the current triple.
If a = b:
only the first two matrices give distinct sorted children
otherwise:
use all three matrices
For each chosen matrix:
compute the transformed triple
keep it only if all three coordinates stay positive
sort the first two coordinates
push the child onto the stack
Return the counter.
Complexity Analysis
- Time: Linear in the number of generated triples; every valid solution is visited once.
- Space: Proportional to the maximum size of the DFS stack.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <algorithm>
#include <array>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
using Matrix = array<array<long long, 3>, 3>;
const Matrix matrices[3] = {
{{{1, -2, 2}, {2, -1, 2}, {2, -2, 3}}},
{{{1, 2, 2}, {2, 1, 2}, {2, 2, 3}}},
{{{-1, 2, 2}, {-2, 1, 2}, {-2, 2, 3}}},
};
tuple<long long, long long, long long> transform(const Matrix& matrix,
long long a,
long long b,
long long c) {
long long x = matrix[0][0] * a + matrix[0][1] * b + matrix[0][2] * c;
long long y = matrix[1][0] * a + matrix[1][1] * b + matrix[1][2] * c;
long long z = matrix[2][0] * a + matrix[2][1] * b + matrix[2][2] * c;
return {x, y, z};
}
int main() {
const long long limit = 75000000LL;
long long count = 0;
vector<tuple<long long, long long, long long>> stack = {{2, 2, 3}};
while (!stack.empty()) {
long long a0, b0, c;
tie(a0, b0, c) = stack.back();
stack.pop_back();
long long a = min(a0, b0);
long long b = max(a0, b0);
if (a + b + c > limit) {
continue;
}
count++;
int childCount = (a == b ? 2 : 3);
for (int i = 0; i < childCount; i++) {
long long x0, y0, z;
tie(x0, y0, z) = transform(matrices[i], a, b, c);
if (x0 <= 0 || y0 <= 0 || z <= 0) {
continue;
}
long long x = min(x0, y0);
long long y = max(x0, y0);
stack.push_back(make_tuple(x, y, z));
}
}
cout << count << '\n';
return 0;
}
"""
Problem 224: Almost Right-angled Triangles II
We need positive solutions of
a^2 + b^2 = c^2 - 1
with a <= b and a + b + c <= 75,000,000.
The Berggren matrices preserve x^2 + y^2 - z^2 = -1. Starting from the root
(2, 2, 3), they generate every positive primitive solution. Because a and b
play symmetric roles, sorted triples only need two children when a = b and all
three otherwise.
"""
MATRICES = (
((1, -2, 2), (2, -1, 2), (2, -2, 3)),
((1, 2, 2), (2, 1, 2), (2, 2, 3)),
((-1, 2, 2), (-2, 1, 2), (-2, 2, 3)),
)
def transform(matrix, triple):
a, b, c = triple
return (
matrix[0][0] * a + matrix[0][1] * b + matrix[0][2] * c,
matrix[1][0] * a + matrix[1][1] * b + matrix[1][2] * c,
matrix[2][0] * a + matrix[2][1] * b + matrix[2][2] * c,
)
def solve():
limit = 75_000_000
count = 0
stack = [(2, 2, 3)]
while stack:
a, b, c = stack.pop()
if a > b:
a, b = b, a
if a + b + c > limit:
continue
count += 1
children = MATRICES[:2] if a == b else MATRICES
for matrix in children:
x, y, z = transform(matrix, (a, b, c))
if x <= 0 or y <= 0 or z <= 0:
continue
if x > y:
x, y = y, x
stack.append((x, y, z))
print(count)
if __name__ == "__main__":
solve()