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

100 篇文章 3 订阅
87 篇文章 1 订阅

Problem 87 : Prime power triples

The smallest number expressible as the sum of a prime square, prime cube, and prime fourth power is 28. In fact, there are exactly four numbers below fifty that can be expressed in such a way:

28 = 22 + 23 + 24
33 = 32 + 23 + 24
49 = 52 + 23 + 24
47 = 22 + 33 + 24

How many numbers below fifty million can be expressed as the sum of a prime square, prime cube, and prime fourth power?

1. 欧拉项目第87道题 质数幂三元组

最小的可以表示为一个质数的平方,加上一个质数的立方,再加上一个质数的四次方的数是28。实际上,在小于50的数中,一共有4个数满足这一性质:

28 = 22 + 23 + 24
33 = 32 + 23 + 24
49 = 52 + 23 + 24
47 = 22 + 33 + 24

在小于五千万的数中,有多少个数可以表示为一个质数的平方,加上一个质数的立方,再加上一个质数的四次方?

2. 求解分析

求解这道题有几个点:第一,使用质数筛子获取质数列表,第二, 一个质数的平方,立方和四次方的幂之和要小于5千万,第三,符合条件的幂之和有可能重复,需要剔除重复的,但如果使用集合,会比较耗时。

第一步:我们找到最大的质数p的质数列表 [2,3, …, p](p2 + 23 + 24 < 50000000)
第二步:枚举判断质数三元组(p1, p2, p3) 且 p12 + p22 + p32 < 50000000
第三步:剔除重复的幂之和, 统计不重复的幂之和的个数。

3. Python 代码实现

Python 代码

# PE0087.py
import math

def createPrimeSieve(n):
    """ create prime sieve and return primes list """
    sieve = [True] * n
    sieve[0] = sieve[1] = False

    for i in range(2, int(n**0.5)+1):
        if True == sieve[i]:
            for j in range(i*i, n, i):
                sieve[j] = False

    return [ i for i in range(1, n) if True==sieve[i] ]
    
def getPrimesList(max_number):
    '''
    find primes list which sum of a prime square, prime cube, 
    and prime fourth power is below fifty million
    '''
    max_prime = int(math.sqrt(max_number - 2**3 - 2**4))
    primes_list = createPrimeSieve(max_prime+1)
    return primes_list

def getNumOfPrimePowerTriples(max_number):
    '''
    max_number is fifty million
    '''
    primes_powers_sum_list = [ 0 ] * max_number
    primes_list = getPrimesList(max_number)
    for prime3 in primes_list:
        prime_fourth_power = prime3**4
        for prime2 in primes_list:
            prime_cube = prime2**3
            sum32 = prime_fourth_power + prime_cube
            if sum32 >= max_number:
                break
            for prime1 in primes_list:
                prime_square = prime1**2
                sum321 = sum32 + prime_square
                if sum321 >= max_number:
                    break
                else:
                    primes_powers_sum_list[sum321] = 1
   
    return sum(primes_powers_sum_list)
                            
def main():
    total = getNumOfPrimePowerTriples(50*10**6)
    print(total, "numbers below fifty million can be expressed as the")
    print("sum of a prime square, prime cube, and prime fourth power.")
    
if  __name__ == '__main__':
    main()

4. C++ 代码实现

C++采用了求解分析的方法,首先通过质数筛子找到所有小于 50万的平方根的质数列表,保存质数列表的时候使用STL vector或者申请内存来保存,然后枚举判断满足条件的质数三元组,当然统计的时候,要剔除重复的幂之和。

实际结果表明:使用STL vector或者申请内存来保存质数,运行时间相差不大。

C++代码 (编译开关为 USE_STL_VECTOR)

#include <iostream>
#include <vector>
#include <cmath>    // pow()
#include <ctime>    // clock()
#include <cstring>  // memset()

using namespace std;

//#define USE_STL_VECTOR

class PE0087
{
private:
    static const int max_number_int = 50000000; // 50 million
    bool *m_primesSieve;

    vector<int> primes_vec;
    int  *m_primesArray = nullptr;
    int  m_numOfPrimes;

    void createPrimeSieve(int max_n);

    int getPrimesList();

public:
    PE0087() { getPrimesList(); };
    ~PE0087() { delete[] m_primesArray; };

    int getNumOfPrimePowerTriples();
    int getNumOfPrimePowerTriples1();
};

// create a prime Sieve of Eratosthenes below max value
void PE0087::createPrimeSieve(int max_n)
{
    m_primesSieve[0] = m_primesSieve[1] = false;

    for (int i = 2; i < (int)sqrt((double)max_n); i++)
    {
        if (true == m_primesSieve[i])
        {
            for (int j = i * i; j < max_n; j += i)
            {
                m_primesSieve[j] = false;
            }
        }
    }
}

int PE0087::getPrimesList()
{
    int max_square_root = (int)sqrt((double)max_number_int);

    m_primesSieve = new bool[max_square_root + 1];
    memset(m_primesSieve, true, (max_square_root + 1) * sizeof(bool));

    createPrimeSieve(max_square_root);

#ifndef USE_STL_VECTOR
    m_primesArray = new int[max_square_root + 1];
    m_numOfPrimes = 0;
#endif

    for (int n = 2; n < max_square_root; n++)
    {
        if (true == m_primesSieve[n])
        {
#ifdef USE_STL_VECTOR
            primes_vec.push_back(n);
#else
            m_primesArray[m_numOfPrimes++] = n;
#endif
        }
    }

    delete[] m_primesSieve;

    return 0;
}

int PE0087::getNumOfPrimePowerTriples1()
{
    double max_number = (double)max_number_int;

    int *PrimePowerTriples = new int[max_number_int + 1];
    memset(PrimePowerTriples, 0, sizeof(int)*(max_number_int + 1));

    for (int i = 0; i < m_numOfPrimes; i++)  // primes vector
    {
        double prime_square = pow((double)m_primesArray[i], 2);
        for (int j = 0; j < m_numOfPrimes; j++)  // prime cube
        {
            double prime_cube = pow((double)m_primesArray[j], 3);

            if (prime_square + prime_cube >= max_number)
            {
                break;
            }

            for (int k = 0; k < m_numOfPrimes; k++) //prime fourth power
            {
                double number = prime_square + prime_cube + pow((double)m_primesArray[k], 4);
                if (number > 0 && number < max_number)
                {
                    PrimePowerTriples[(int)number] = 1;
                }
                else
                {
                    break;
                }
            }
        }
    }

    int total = 0;
    for (int n = 1; n < max_number_int; n++)
    {
        if (1 == PrimePowerTriples[n])
        {
            total++;
        }
    }

    delete[] PrimePowerTriples;

    return total;
}

int PE0087::getNumOfPrimePowerTriples()
{
    double max_number = (double)max_number_int;

    int *PrimePowerTriples = new int[max_number_int];
    memset(PrimePowerTriples, 0, sizeof(int)*max_number_int);

    for (auto prime1 : primes_vec)  // primes vector
    {
        double prime_square = prime1 * prime1;
        for (auto prime2 : primes_vec)  // prime cube
        {
            double prime_cube = pow((double)prime2, 3);

            if (prime_square + prime_cube >= max_number)
            {
                break;
            }

            for (auto prime3 : primes_vec) //prime fourth power
            {
                double number = prime_square + prime_cube + pow((double)prime3, 4);
                if (number < max_number)
                {
                    PrimePowerTriples[(int)number] = 1;
                }
                else
                {
                    break;
                }
            }
        }
    }

    int total = 0;
    for (int n = 0; n < max_number_int; n++)
    {
        if (1 == PrimePowerTriples[n])
        {
            total++;
        }
    }

    delete [] PrimePowerTriples;

    return total;
}

int main()
{
    clock_t start = clock();

    PE0087 pe0087;

#ifdef USE_STL_VECTOR
    int total = pe0087.getNumOfPrimePowerTriples();
#else
    int total = pe0087.getNumOfPrimePowerTriples1();
#endif

    cout << total << " below fifty million can be expressed as the sum" << endl;
    cout << "of a prime square, prime cube, and prime fourth power" << endl;

    clock_t finish = clock();
    double duration = (double)(finish - start) / CLOCKS_PER_SEC;
    cout << "C/C++ running time: " << duration << " seconds" << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值