174 lines
5.8 KiB
C++
174 lines
5.8 KiB
C++
/*
|
|
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.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <vector>
|
|
#include <unordered_set>
|
|
#include <cmath>
|
|
|
|
using namespace std;
|
|
|
|
vector<unsigned int> sieve(int n){
|
|
if(n < 2) return vector<unsigned int>();
|
|
|
|
vector<bool> ns(n, true);
|
|
|
|
for(int i = 2; i <= sqrt(n); ++i){
|
|
if(ns[i]){
|
|
int j = pow(i, 2);
|
|
|
|
while(j < n){
|
|
ns[j] = false;
|
|
j += i;
|
|
}
|
|
}
|
|
}
|
|
|
|
vector<unsigned int> primes;
|
|
|
|
for(size_t i = 2; i < ns.size(); ++i){
|
|
if(ns[i]) primes.push_back(i);
|
|
}
|
|
|
|
return primes;
|
|
}
|
|
|
|
// Wheel factorization primality test
|
|
bool isPrime(const unsigned long long n){
|
|
if(n % 2 == 0 || n % 3 == 0 || n % 5 == 0){
|
|
return n == 2 || n == 3 || n == 5;
|
|
}
|
|
|
|
const unsigned int delta[] = {6, 4, 2, 4, 2, 4, 6, 2};
|
|
unsigned long long i = 7;
|
|
int pos = 1;
|
|
|
|
while(i*i <= n){
|
|
if(n % i == 0){
|
|
return false;
|
|
}
|
|
i += delta[pos];
|
|
pos = (pos + 1) & 7;
|
|
}
|
|
return n > 1;
|
|
}
|
|
|
|
int intLength(const unsigned long long n){
|
|
return trunc(log10(n)) + 1;
|
|
}
|
|
|
|
unsigned long long combine(const unsigned long long n, const unsigned long long m){
|
|
unsigned long long res = n;
|
|
int mLength = intLength(m);
|
|
|
|
res *= pow(10, mLength);
|
|
res += m;
|
|
|
|
return res;
|
|
}
|
|
|
|
bool match(unsigned long long n, unsigned long long m){
|
|
return isPrime(combine(n, m)) && isPrime(combine(m, n));
|
|
}
|
|
|
|
|
|
|
|
// Assume that the size of all unordered sets is equal, otherwise this doesn't work
|
|
// WARNING: this is not an efficient function and it might even be bugged
|
|
vector<unordered_set<unsigned int>> aPriori(const vector<unordered_set<unsigned int>> & primePairs, const unordered_set<unsigned int> & primes){
|
|
if(primePairs.empty()) return vector<unordered_set<unsigned int>>();
|
|
|
|
int setSize = primePairs[0].size();
|
|
vector<unordered_set<unsigned int>> result;
|
|
|
|
for(size_t i = 0; i < primePairs.size(); ++i){
|
|
for(size_t j = min(i + 1, primePairs.size() - 1); j < primePairs.size(); ++j){
|
|
unordered_set<unsigned int> combinationSet(primePairs[i]);
|
|
|
|
for(int k : primePairs[j]){
|
|
combinationSet.insert(k);
|
|
}
|
|
|
|
if(combinationSet.size() == setSize + 1){
|
|
bool allPrimes = true;
|
|
|
|
for(auto it = combinationSet.begin(); it != combinationSet.end(); ++it){
|
|
for(auto jt = combinationSet.begin(); jt != combinationSet.end(); ++jt){
|
|
if(it != jt){
|
|
int p1 = combine(*it, *jt), p2 = combine(*jt, *it);
|
|
|
|
if(primes.find(p1) == primes.end() || primes.find(p2) == primes.end()){
|
|
allPrimes = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(allPrimes) result.push_back(combinationSet);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int main(){
|
|
std::cout << "Hello this is Patrick" << endl;
|
|
auto start = chrono::high_resolution_clock::now();
|
|
|
|
auto primeVector = sieve(10000);
|
|
// unordered_set<unsigned int> primes(primeVector.begin(), primeVector.end());
|
|
bool foundSum = false;
|
|
|
|
for(auto it = primeVector.begin(); it != primeVector.end(); ++it){
|
|
if(foundSum) break;
|
|
|
|
vector<int> candidateDoubles(it + 1, primeVector.end());
|
|
|
|
for(auto jt = candidateDoubles.begin(); jt != candidateDoubles.end(); ++jt){
|
|
if(foundSum) break;
|
|
|
|
if(match(*it, *jt)){
|
|
vector<int> candidateTriples(jt + 1, candidateDoubles.end());
|
|
|
|
for(auto kt = candidateTriples.begin(); kt != candidateTriples.end(); ++kt){
|
|
if(foundSum) break;
|
|
|
|
if(match(*it, *kt) && match(*jt, *kt)){
|
|
vector<int> candidateQuartets(kt + 1, candidateTriples.end());
|
|
|
|
for(auto lt = candidateQuartets.begin(); lt != candidateQuartets.end(); ++lt){
|
|
if(foundSum) break;
|
|
|
|
if(match(*it, *lt) && match(*jt, *lt) && match(*kt, *lt)){
|
|
vector<int> candidateQuintets(lt + 1, candidateQuartets.end());
|
|
|
|
for(auto mt = candidateQuintets.begin(); mt != candidateQuintets.end(); ++mt){
|
|
if(match(*it, *mt) && match(*jt, *mt) && match(*kt, *mt) && match(*lt, *mt)){
|
|
std::cout << *it << " " << *jt << " " << *kt << " " << *lt << " " << *mt << " equals: " << *it + *jt + *kt + *lt + *mt << endl;
|
|
|
|
foundSum = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// For checking the result of four
|
|
// cout << *it << " " << *jt << " " << *kt << " " << *lt << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto duration = chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - start);
|
|
std::cout << (float)duration.count()/1000 << endl;
|
|
|
|
return 0;
|
|
} |