Project Euler Problem 60 (C++和Python)
阿新 • • 發佈:2018-12-26
Problem 60 : Prime pair sets
The primes 3, 7, 109, and 673, are quite remarkable. By taking any two primes and concatenating them in any order the result will always be prime. For example, taking 7 and 109, both 7109 and 1097 are prime. The sum of these four primes, 792, represents the lowest sum for a set of four primes with this property.
Find the lowest sum for a set of five primes for which any two primes concatenate to produce another prime.
C++ 程式碼
#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <iterator>
#include <cmath>
#include <cassert>
using namespace std;
#define CPP_11
//#define UNIT_TEST
class PE0060
{
private:
vector<int> m_primes_v = {};
bool checkPrime(int number);
void getPrimesVector(int max);
vector<int> getDigits(int number);
int getNumberByDigits(vector<int>& digits);
bool checkConcatenatedPrimes (int prime1, int prime2);
public:
PE0060() { getPrimesVector(10000); }
bool checkPrimesPair(int prime1, int prime2);
int findLowestSumOfFivePrimes();
};
bool PE0060::checkPrime(int number)
{
double squareRoot = sqrt((double)number);
if (number < 2 || number % 2 == 0 && 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;
}
vector<int> PE0060::getDigits(int number)
{
vector<int>digit_vec;
while (number > 0)
{
digit_vec.push_back(number % 10); // 197 => digits: 7, 9, 1
number /= 10;
}
return digit_vec;
}
int PE0060::getNumberByDigits(vector<int>& digits)
{
vector<int>::reverse_iterator iter = digits.rbegin();
int number = 0;
while (iter != digits.rend())
{
number = number * 10 + *iter; // digits: 7, 9, 1 => 197
iter++;
}
return number;
}
bool PE0060::checkConcatenatedPrimes(int prime1, int prime2)
{
#ifndef CPP_11
vector<int> prime1_vec = getDigits(prime1);
vector<int> prime2_vec = getDigits(prime2);
vector<int>::iterator iter;
for (iter = prime1_vec.begin(); iter != prime1_vec.end(); iter++)
{
prime2_vec.push_back(*iter);
}
int number = getNumberByDigits(prime2_vec);
return checkPrime(number);
#else
string s = to_string(prime1) + to_string(prime2);
return checkPrime(stoi(s)); // prime1:109, prime2:7, concat number: 1097
#endif
}
bool PE0060::checkPrimesPair(int prime1, int prime2)
{
if (false == checkConcatenatedPrimes(prime1, prime2) ||
false == checkConcatenatedPrimes(prime2, prime1))
{
return false;
}
return true;
}
void PE0060::getPrimesVector(int max)
{
for (int n = 3; n < max; n++)
{
if (true == checkPrime(n))
{
m_primes_v.push_back(n);
}
}
}
int PE0060::findLowestSumOfFivePrimes()
{
int size = m_primes_v.size();
for (int i = 1; i < size - 4; i++) // skip first prime 2
{
for (int j = i + 1; j < size - 3; j++)
{
if (false == checkPrimesPair(m_primes_v[i], m_primes_v[j]))
{
continue;
}
for (int k = j + 1; k < size - 2; k++)
{
if (false == checkPrimesPair(m_primes_v[i], m_primes_v[k]) ||
false == checkPrimesPair(m_primes_v[j], m_primes_v[k]))
{
continue;
}
for (int n = k + 1; n < size - 1; n++)
{
if (false == checkPrimesPair(m_primes_v[i], m_primes_v[n]) ||
false == checkPrimesPair(m_primes_v[j], m_primes_v[n]) ||
false == checkPrimesPair(m_primes_v[k], m_primes_v[n]))
{
continue;
}
for (int m = n + 1; m < size; m++)
{
if (false==checkPrimesPair(m_primes_v[i],m_primes_v[m]) ||
false==checkPrimesPair(m_primes_v[j],m_primes_v[m]) ||
false==checkPrimesPair(m_primes_v[k],m_primes_v[m]) ||
false==checkPrimesPair(m_primes_v[n],m_primes_v[m]))
{
continue;
}
#ifdef UNIT_TEST
cout << "Five primes chain: " << m_primes_v[i] << ", ";
cout << m_primes_v[j] << ", " << m_primes_v[k] << ", ";
cout << m_primes_v[n] << ", " << m_primes_v[m] << endl;
#endif
return (m_primes_v[i] + m_primes_v[j] + \
m_primes_v[k] + m_primes_v[n] + m_primes_v[m]);
}
}
}
}
}
return 0;
}
int main()
{
PE0060 pe0060;
assert(true == pe0060.checkPrimesPair(109, 7));
int sum = pe0060.findLowestSumOfFivePrimes();
cout << "The lowest sum for a set of five primes is " << sum << endl;
return 0;
}
Python
import itertools
def check_prime(x):
"""check whether integer x is a prime """
if x < 2 or (x != 2 and x%2 == 0):
return False
for i in range (3, int(x**0.5)+1, 2):
if 0 == x % i:
return False
return True
def create_primes_sieve(n):
""" Returns a list of primes < n """
sieve = [True] * int(n/2)
for i in range(3, int(n**0.5)+1, 2):
if True == sieve[int(i/2)]:
sieve[int(i*i/2)::i] = [False] * (int((n-i*i-1)/(2*i))+1)
return [2] + [ 2*i+1 for i in range(1, int(n/2)) if True == sieve[i] ]
def make_primes_chain(chain, primes_list, set_size):
"""use recusive method to find five primes chain """
if len(chain) == set_size:
return chain
for p in primes_list:
if p > chain[-1] and True == check_all_concatenated_primes(chain+[p]):
new_chain = make_primes_chain(chain+[p], primes_list, set_size)
if new_chain:
return new_chain
return []
def check_all_concatenated_primes(chain):
"""
check whether any two primes in chain can concatenate a prime
return all(check_prime(int(str(p[0])+str(p[1]))) \
for p in iter.permutations(chain, 2))
"""
for p in itertools.permutations(chain, 2):
if False == check_prime(int(str(p[0])+str(p[1]))):
return False
return True
def main():
primes_list = create_primes_sieve(10000)
chain = []
while not chain:
chain = make_primes_chain([primes_list.pop(0)], primes_list, 5)
print("The lowest sum for a set of five primes", chain, "is", sum(chain))
if __name__ == '__main__':
main()