Project Euler Problem 75 (C++和Python代码实现和解析)

探讨了如何找出特定长度下能唯一形成整数边直角三角形的问题,通过生成毕达哥拉斯三元组并筛选符合条件的组合,提供了C++和Python的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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()
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值