Project Euler Problem 37
阿新 • • 發佈:2018-11-02
Problem 37 : Truncatable primes
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
#include <iostream>
#include <vector>
#include <iterator>
#include <cmath>
#include <ctime>
#include <cassert>
using namespace std;
#define UNIT_TEST
class PE0037
{
private:
static const int m_MAX = 1000000; // one million
bool *m_Sieve;
void createPrimeSieve();
int m_digits[10]; // save digits of number below one million
bool checkPrime(int number) const;
int getDigits(int number);
int getNumberByDigits(vector<int>digits);
int getNumberByDigits(int first, int last);
public:
PE0037() { m_Sieve = new bool [m_MAX+1]; createPrimeSieve(); }
~PE0037() { delete [] m_Sieve; }
bool checkTruncatablePrimes(int number);
int getSumOfTruncatablePrimes();
};
// create a prime Sieve of Eratosthenes below max value
void PE0037::createPrimeSieve()
{
memset(m_Sieve, true, (m_MAX+1)*sizeof(bool));
m_Sieve[0] = m_Sieve[1] = false;
for (int i=2; i<=(int)sqrt((double)m_MAX); i++)
{
if (true == m_Sieve[i])
{
for (int j=i*i; j<m_MAX; j+=i)
{
m_Sieve[j] = false;
}
}
}
}
bool PE0037::checkPrime(int number) const
{
return m_Sieve[number];
}
int PE0037::getDigits(int number)
{
int numOfDigits = 0;
while(number> 0)
{
m_digits[numOfDigits++] = number%10; // 3797 => digits: 7, 9, 7, 3
number /= 10;
}
return numOfDigits;
}
int PE0037::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, 7, 3 => 3797
iter++;
}
return number;
}
int PE0037::getNumberByDigits(int first, int last)
{
int number = 0;
for(int i=last; i>=first; i--)
{
number = number*10 + m_digits[i]; // digits: 7, 9, 7, 3 => 3797
}
return number;
}
bool PE0037::checkTruncatablePrimes(int number)
{
if (false == checkPrime(number))
{
return false;
}
int numOfDigits = getDigits(number);
#ifdef USE_VECTOR
vector<int> digits_v(numOfDigits);
digits_v.assign(m_digits, m_digits+numOfDigits);
// work from right to left, e.g. 3797, 379, 37, and 3 because digits_v={7,9,7,3}
vector<int>::iterator iter = digits_v.begin();
while (iter != digits_v.end())
{
vector<int>dv(iter, digits_v.end());
int n = getNumberByDigits(dv);
if (false == checkPrime(n))
{
return false;
}
iter++;
}
// work from left to right, e.g. 3797, 797, 97, and 7 because digits_v={7,9,7,3}
vector<int>::iterator iter1 = digits_v.end();
while (iter1 != digits_v.begin())
{
vector<int> dv(digits_v.begin(), iter1);
int n = getNumberByDigits(dv);
if (false == checkPrime(n))
{
return false;
}
iter1--;
}
#else
for(int i=0; i<=numOfDigits-1; i++)
{
int n = getNumberByDigits(i, numOfDigits-1);
if (false == checkPrime(n))
{
return false;
}
}
for(int i=numOfDigits-1; i>=0; i--)
{
int n = getNumberByDigits(0, i);
if (false == checkPrime(n))
{
return false;
}
}
#endif
return true;
}
int PE0037::getSumOfTruncatablePrimes()
{
int sumOfTruncatablePrimes = 0;
int numOfTruncatablePrimes = 0;
for(int number=10;numOfTruncatablePrimes<11;number++)
{
if (true == checkTruncatablePrimes(number))
{
sumOfTruncatablePrimes += number;
numOfTruncatablePrimes++;
#ifdef UNIT_TEST
cout << number << " is " << numOfTruncatablePrimes;
cout << "th truncatable prime." << endl;
#endif
}
}
return sumOfTruncatablePrimes;
}
int main()
{
clock_t start = clock();
PE0037 pe0037;
assert(true == pe0037.checkTruncatablePrimes(3797));
cout << "The sum of the only primes that are both truncatable" << endl;
cout << "from left to right and right to left is " ;
cout << pe0037.getSumOfTruncatablePrimes() << endl;
clock_t finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "C/C++ application running time: " << duration << " seconds" << endl;
return 0;
}