Project Euler Problem 35
阿新 • • 發佈:2018-11-02
Problem 35 : Circular primes
The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.
There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.
How many circular primes are there below one million?
#include <iostream>
#include <vector>
#include <set>
#include <iterator>
#include <cmath>
#include <ctime>
#include <cassert>
using namespace std;
// #define UNIT_TEST
// #define USE_DIGITS_VECTOR
class PE0035
{
private:
static const int m_MAX = 1000000; // one millions
bool *m_Sieve;
void createPrimeSieve();
bool checkPrime(long long number);
bool checkDigitZero(int number);
vector<int> getDigits(long int number);
long getNumberByDigits(vector<int>& digits);
bool checkRotationDigits(long int number);
public:
PE0035( ) { m_Sieve = new bool [m_MAX+1]; createPrimeSieve(); }
~PE0035() { delete [] m_Sieve; }
int getCircularPrimes(int number);
};
// create a prime Sieve of Eratosthenes below max value
void PE0035::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 PE0035::checkPrime(long long number)
{
long double squareRoot=sqrtl((long double)number);
if (number<2 || number%2 == 0 && number>2)
{
return false;
}
for(long int i=3;i<=(long long)squareRoot;i+=2) // 3, 5, 7, ...(int)squareRoot
{
if (number % i == 0)
{
return false;
}
}
return true;
}
vector<int> PE0035::getDigits(long int number)
{
vector<int> digit_vec;
while(number> 0)
{
digit_vec.push_back(number%10); // 197 => reverse digits: 7, 9, 1
number /= 10;
}
return digit_vec;
}
long PE0035::getNumberByDigits(vector<int>& digits)
{
vector<int>::reverse_iterator iter=digits.rbegin();
long number = 0;
while(iter!=digits.rend())
{
number = number*10 + *iter; // digits: 7, 9, 1 => 197
iter++;
}
return number;
}
bool PE0035::checkRotationDigits(long int number)
{
#ifdef USE_DIGITS_VECTOR
if (number > 10)
{
vector<int> digits_v;
while(number> 0)
{
if (0 == number%10)
{
return false;
}
digits_v.push_back(number%10); // 197 => digits: 7, 9, 1
number /= 10;
}
vector<int>::iterator iter;
int digit;
for(unsigned int i=1; i<digits_v.size(); i++)
{
iter = digits_v.begin();
digit = *iter;
digits_v.erase(iter);
digits_v.push_back(digit);
number = getNumberByDigits(digits_v);
if (false == m_Sieve[number])
{
return false;
}
}
}
#else // USE_DIGITS_ARRAY
int digitsArray[6]; // max number 999999
int numOfDigits = 0;
while (number > 0)
{
if (0 == number%10)
{
return false;
}
digitsArray[numOfDigits++] = number%10;
number /= 10;
}
// note that digitsArray stores reverse digits of number
// digitsArray[] = {1, 3, 3, 9, 9, 9} while number is 999331
for (int i=numOfDigits-1; i>0; i--)
{
number = 0;
for (int j=numOfDigits+i-1; j>=i; j--)
{
number = number*10 + digitsArray[j%numOfDigits];
}
if (false == m_Sieve[number])
{
return false;
}
}
#endif
return true;
}
int PE0035::getCircularPrimes(int number=m_MAX)
{
int numOfCircularPrimes = 0;
for(long n=2; n<number; n++)
{
if (true==m_Sieve[n] && true==checkRotationDigits(n))
{
#ifdef UNIT_TEST
cout << "The number " << n << " is called a circular prime." << endl;
#endif
numOfCircularPrimes++;
}
}
return numOfCircularPrimes;
}
int main()
{
clock_t start = clock();
PE0035 pe0035;
assert(13 == pe0035.getCircularPrimes(100));
cout << "There are " << pe0035.getCircularPrimes();
cout << " circular primes below one million" << endl;
clock_t finish = clock();
double duration = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "C/C++ application running time: " << duration << " seconds" << endl;
return 0;
}