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()