Problem 75 : Singular integer right triangles
It turns out that 12 cm is the smallest length of wire that can be bent to form an integer sided right angle triangle in exactly one way, but there are many more examples.
12 cm: (3,4,5)
24 cm: (6,8,10)
30 cm: (5,12,13)
36 cm: (9,12,15)
40 cm: (8,15,17)
48 cm: (12,16,20)
In contrast, some lengths of wire, like 20 cm, cannot be bent to form an integer sided right angle triangle, and other lengths allow more than one solution to be found; for example, using 120 cm it is possible to form exactly three different integer sided right angle triangles.
120 cm: (30,40,50), (20,48,52), (24,45,51)
Given that L is the length of the wire, for how many values of L ≤ 1,500,000 can exactly one integer sided right angle triangle be formed?
1. 欧拉项目第75道题 单个的整数边直角三角形
事实证明,12厘米是最小的线长,能够以精确地方式弯曲形成一个整数边直角三角形,但还有更多的例子。
12 cm: (3,4,5)
24 cm: (6,8,10)
30 cm: (5,12,13)
36 cm: (9,12,15)
40 cm: (8,15,17)
48 cm: (12,16,20)
相反,一些线的长度,如20厘米,不能弯曲成整数边直角三角形,而其他长度则允许找到一个以上的解;例如,使用120厘米就可以形成三个不同的整数边直角三角形。
120 cm: (30,40,50), (20,48,52), (24,45,51)
假定L是线的长度,对于L≤1,500,000,可以形成多少单个的整数边直角三角形?
2. 求解分析
我们知道Project Euler Problem 39整数边直角三角形也有判断一个给定的周长p,最多有多少整数边直角三角形。
但是 p ≤ 1000, 现在 L≤1500000, 我们需要找到其他方法或规律来解决这道题。
请参考 Pythagorean triple - Wikipedia来生成毕达哥拉斯三元组。
3. C++ 代码实现
我们根据求解分析的方法,使用下面的方法,产生a, b,c, 然后判断(a, b, c)是否是最简三角形,然后找到周长为p的k倍的三角形,最后统计只有单个整数边的直角三角形个数。
a = k*(m2 - n2), b = k*(2mn), c = k*(m2 + n2)
where m, n, and k are positive integers with m > n, (m − n) odd, and with m
and n coprime.
C++代码
#include <iostream>
#include <ctime>
#include <cmath>
#include <cassert>
using namespace std;
// #define UNIT_TEST
class PE0075
{
private:
int gcd(int a, int b);
public:
int findIntegerSidedRightAngleTriangles(int max_length);
};
int PE0075::gcd(int a, int b)
{
int tmp;
while (b != 0)
{
tmp = a;
a = b;
b = tmp % b;
}
return a;
}
int PE0075::findIntegerSidedRightAngleTriangles(int max_length)
{
int a,b,c,p;
int *rightTriangles = new int [max_length+1];
memset(rightTriangles, 0, sizeof(int)*(max_length+1));
for(int m=2; m<=(int)sqrt((max_length-4)/2.0); m++)
{
for(int n=1; n<m; n++)
{
if ((m - n) % 2 == 1 && 1 == gcd(m, n))
{
//a = m^2-n^2,b = 2mn, c = m^2 + n^2
a = m*m-n*n;
b = 2*m*n;
c = m*m+n*n;
p = a+b+c; // p is the perimeter of a right angle triangle
if(p<=max_length && gcd(c,gcd(b, a))==1)
{
for(int s=p; s<=max_length; s+=p)
{
rightTriangles[s]++;
#ifdef UNIT_TEST
cout << s << " : " << rightTriangles[s] << endl;
int k = s/sum;
cout << s << " (" << k*a << ", " << k*b << ", " << k*c << ")" << endl;
#endif
}
}
}
}
}
int numOfTriangles = 0;
for(int s=1; s<=max_length; s++)
{
if(1 == rightTriangles[s]) // singular integer right triangle
{
numOfTriangles++;
}
}
delete [] rightTriangles;
return numOfTriangles;
}
int main()
{
clock_t start = clock();
PE0075 pe0075;
assert(13 == pe0075.findIntegerSidedRightAngleTriangles(120));
const int L = 1500000;
cout << "For L <=" << L << ", " << pe0075.findIntegerSidedRightAngleTriangles(L);
cout << " exactly one integer sided right angle triangles can be formed." << endl;
clock_t finish = clock();
double duration=(double)(finish - start) / CLOCKS_PER_SEC;
cout << "C++ application running time: " << duration << " seconds" << endl;
return 0;
}
4. Python 代码实现
Python采用与C++一样的的方法实现。
Python 代码
import time
import math
def gcd(a, b):
"""
Compute the greatest common divisor of a and b.
"""
while b != 0:
a, b = b, a % b
return a
def findIntegerSidedRightAngleTriangles(max_length):
numOfTriangles, rightTriangles = 0, [0] * (max_length+1)
# p = 2*m*m + 2*m*n <= max_length, n >= 1, m > n so m>=2 and
for m in range(2, int(math.sqrt((max_length-4)//2))):
for n in range (1, m): # m > n
# check whether (m − n) is odd and m & n are co-prime
if (m - n) % 2 == 1 and 1 == gcd(m, n):
a, b, c = m*m-n*n, 2*m*n, m*m+n*n
p = a+b+c # the perimeter of a right angle triangle
if p <= max_length and 1 == gcd(c, gcd(b, a)):
#for k in range (1, (max_length+1)//p+1): ## working
# rightTriangles[p*k] += 1
for s in range(p, max_length+1, p): ## faster
rightTriangles[s] += 1
numOfTriangles = len([s for s in range(1, max_length+1) if 1 == rightTriangles[s]])
return numOfTriangles
def main():
start = time.process_time()
assert(13 == findIntegerSidedRightAngleTriangles(120));
L = 1500000
print("For L <= %d," % L, findIntegerSidedRightAngleTriangles(L), end='')
print(" exactly one integer sided right angle triangles can be formed.")
end = time.process_time()
print('CPU processing time :', end-start)
if __name__ == '__main__':
main()