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

本文探讨了如何找出能以超过五千种不同方式写为质数之和的最小数值,通过对欧拉项目第77题的深入解析,采用生成函数方法高效解决了这一问题,并提供了C++及Python代码实现。

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

Problem 77 : Prime summations

It is possible to write ten as the sum of primes in exactly five different ways:

7 + 3
5 + 5
5 + 3 + 2
3 + 3 + 2 + 2
2 + 2 + 2 + 2 + 2

What is the first value which can be written as the sum of primes in over five thousand different ways?

1. 欧拉项目第77道题 质数的求和

可以以精确的五种不同的方式将10写为素数的和:

7 + 3
5 + 5
5 + 3 + 2
3 + 3 + 2 + 2
2 + 2 + 2 + 2 + 2

可以以超过五千种不同的方式被写为素数的总和的第一个数是什么?

2. 求解分析

可以参考 Problem 76 : Counting summations

这道题跟76题很类似,都适合用生成函数或母函数求解。

不同的地方是:76题的数组fact[]是保存 [1, 2, 3, …, 4,…], 但77题数组primes是保存的质数 [2, 3, 5, 7, …]。

通过母函数计算过后,然后找到大于5000的第一个数就是答案。

这道用母函数来实现,相比其他方法很容易扩展,效率很高。例如:找到大于500000的第一个数是多少?代码可能需要修改的地方是常数max_n的值。

3. C++ 代码实现

C++ 代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <ctime>

using namespace std;

class PE0077
{
private:
    static const int max_n = 1000;
    int  mul[max_n + 1] = { 0 };

    bool checkPrime(int number);
    void generateFunctionProcessing();

public:
    int findFirstNumberOverWays(int over_ways, int& ways);

};

bool PE0077::checkPrime(int number)
{
    double squareRoot = sqrt((double)number);

    if (number % 2 == 0 && number != 2 || number < 2)
    {
        return false;
    }

    for (int i = 3; i <= (int)squareRoot; i += 2)  // 3, 5, 7, ...(int)squareRoot
    {
        if (number % i == 0)
        {
            return false;
        }
    }

    return true;
}

void PE0077::generateFunctionProcessing()
{
    int numOfPrimes = 0;
    int tmp[max_n + 1] = { 0 };
    int primes[max_n + 1];

    mul[0] = 1;

    for (int i = 2; i < max_n; i++)
    {
        if (true == checkPrime(i))
        {
            primes[numOfPrimes++] = i;
        }
    }

    for (int i = 0; i < numOfPrimes; i++)
    {
        memset(tmp, 0, sizeof(tmp));  // initialize array tmp[]

        for (int j = 0; j <= max_n; j += primes[i]) // j power
        {
            for (int k = 0; k + j <= max_n; k++)    // k power
            {
                tmp[k + j] += mul[k];
            }
        }
        copy(tmp, tmp + max_n, mul);  // copy array tmp[] to array mul[]
    }
}

int PE0077::findFirstNumberOverWays(int over_ways, int& ways)
{
    generateFunctionProcessing();

    int i = 0;
    for (i = 2; i < max_n; i++)
    {
        if (mul[i] >= over_ways)
        {
            ways = mul[i];
            break;
        }
    }
    return i;
}

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

    PE0077 pe0077;

    int ways = 0;
    int firstNum = pe0077.findFirstNumberOverWays(5000, ways);
    cout << firstNum << " is the first number which can be written as " << endl;
    cout << "the sum of primes in over " << ways << " different ways." << endl;

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

    return 0;
}

4. Python代码实现

Python 代码

import time
    
class PE0077(object):
    def __init__(self):
        """ 
        max_n could be adjusted according to your rquirement, 
        for over different ways 5000, 100 is enough 
        """
        self.max_n    = 500
        self.mul_list = [0] * (self.max_n + 1)

    def checkPrime(self, number):
        squareRoot = int(number**0.5)
    
        if number % 2 == 0 and number != 2 or number < 2:
            return False

        for i in range(3, squareRoot+1, 2): # 3, 5, 7, ...(int)squareRoot
            if number % i == 0:
                return False

        return True

    def generateFunctionProcessing(self):
		# initialize tmp_list[]
        tmp_list = [0] * (self.max_n+1)

        primes_list = [ n for n in range(2, self.max_n+1) \
            if True == self.checkPrime(n) ]

        self.mul_list[0], numOfPrimes = 1, len(primes_list)
     
        for i in range(numOfPrimes):   
            j = 0
            while j <= self.max_n:                   # j power
                for k in range(self.max_n-j+1):      # k power
                    tmp_list[k+j] += self.mul_list[k]
                j += primes_list[i]
    
            for k in range(self.max_n+1):
                self.mul_list[k] = tmp_list[k]  # copy tmp_list[] to mul_list[]
                tmp_list[k]      = 0            # initialize tmp_list[]

    def findFirstNumberOverWays(self, waysThreshold):
        self.generateFunctionProcessing()

        for i in range(2, self.max_n):
            if self.mul_list[i] >= waysThreshold:
                return [i, self.mul_list[i]]
        
        return [0, 0]

def main():
    start = time.process_time()
    
    pe0077 = PE0077()

    ans = pe0077.findFirstNumberOverWays(5000)
    print("%d is the first number which can be written as " % ans[0])
    print("the sum of primes in over %d different ways." %ans[1])

    end = time.process_time()
    print('CPU processing time : %.5f' %(end-start))

if  __name__ == '__main__':
    main()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值