forked from nayuki/Project-Euler-solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathp094.java
More file actions
80 lines (72 loc) · 2.98 KB
/
p094.java
File metadata and controls
80 lines (72 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
* Solution to Project Euler problem 94
* Copyright (c) Project Nayuki. All rights reserved.
*
* https://www.nayuki.io/page/project-euler-solutions
* https://github.com/nayuki/Project-Euler-solutions
*/
public final class p094 implements EulerSolution {
public static void main(String[] args) {
System.out.println(new p094().run());
}
/*
* Consider an arbitrary almost equilateral triangle with side lengths (c, c, c +/- 1).
* Split it down the middle to get a right triangle, and label the new sides.
* /\ /|
* c / \ c c / | b
* / \ --> / |
* -------- -----
* c +/- 1 a
* Note that a = (c +/- 1) / 2, and a^2 + b^2 = c^2 (Pythagorean theorem).
*
* We know that c is an integer. The area of the original triangle is a*b,
* which is an integer by definition from the problem statement.
* - If a is an integer, then b is an integer (so that a*b is an integer),
* thus (a,b,c) is a Pythagorean triple.
* - Otherwise a is an integer plus a half, then b must be even,
* but a^2 + b^2 is not an integer, which contradicts c being an integer.
*
* Conversely, consider an arbitrary Pythagorean triple (a,b,c).
* If 2a = c +/- 1, then we can form an almost equilateral triangle:
* /|\
* c / | \ c
* / | \
* ---------
* 2a
* For this to happen, the Pythagorean triple must be primitive. Because if not,
* then a = 0 mod k and c = 0 mod k for some k > 1, which means 2a = 0 mod k which
* cannot equal c +/- 1 = +/- 1 mod k. So we only need to generate primitive triples.
*
* Pythagorean triples theorem:
* Every primitive Pythagorean triple with a odd and b even can be expressed as
* a = st, b = (s^2-t^2)/2, c = (s^2+t^2)/2, where s > t > 0 are coprime odd integers.
*/
private static final int LIMIT = Library.pow(10, 9);
public String run() {
long sum = 0;
/*
* What search range do we need?
* c = (s^2+t^2)/2. Perimeter = p = 3c +/- 1 = 3/2 (s^2+t^2) +/- 1 <= LIMIT.
* We need to keep the smaller perimeter within limit for
* the search to be meaningful, so 3/2 (s^2+t^2) - 1 <= LIMIT.
* With t < s, we have that s^2+t^2 < 2s^2, so 3/2 (s^2+t^2) - 1 < 3s^2 - 1.
* Therefore it is sufficient to ensure that 3s^2 - 1 <= LIMIT, i.e. s^2 <= (LIMIT+1)/3.
*/
for (int s = 1; s * s <= (LIMIT + 1) / 3; s += 2) {
for (int t = s - 2; t > 0; t -= 2) {
if (Library.gcd(s, t) == 1) {
int a = s * t;
int b = (s * s - t * t) / 2;
int c = (s * s + t * t) / 2;
if (a * 2 == c - 1) { int p = c * 3 - 1; if (p <= LIMIT) sum += p; }
if (a * 2 == c + 1) { int p = c * 3 + 1; if (p <= LIMIT) sum += p; }
// Swap the roles of a and b and try the same tests
// Note that a != b, since otherwise c = a * sqrt(2) would be irrational
if (b * 2 == c - 1) { int p = c * 3 - 1; if (p <= LIMIT) sum += p; }
if (b * 2 == c + 1) { int p = c * 3 + 1; if (p <= LIMIT) sum += p; }
}
}
}
return Long.toString(sum);
}
}