Project Euler Problem 51 (C++和Python)

本文探讨了一种数学问题,即寻找最小的质数,通过替换其部分数字(不一定是相邻的)为相同的数字,该质数能成为八个质数值家族的一部分。文章提供了使用C++和Python实现的算法代码,用于解决这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem 51: Prime digit replacements

By replacing the 1st digit of the 2-digit number *3, it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.

By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit number is the first example having seven primes among the ten generated numbers, yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993. Consequently 56003, being the first member of this family, is the smallest prime with this property.

Find the smallest prime which, by replacing part of the number (not necessarily adjacent digits) with the same digit, is part of an eight prime value family.

C++ 代码

#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <iterator>
#include <cmath>
#include <cassert>

using namespace std;

class PE0051
{
private:
    bool checkPrime(int number);
    bool getDigitsOfPrime(int prime, int numOfDigits, int numOfSameDigits, 
                          vector<int>& digit_v, int& sameDigit, 
                          vector<int>& sameDigit_pos);
    bool checkPosInVector(int pos, vector<int>pos_vec);

public:
    int getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits,
                               int numOfPrimes);
};

bool PE0051::checkPrime(int number)
{
    long double squareRoot=sqrt((long 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;
}

bool PE0051::getDigitsOfPrime(int prime, int numOfDigits, int numOfSameDigits,
                              vector<int>& digit_v, int & sameDigit, 
                              vector<int>& sameDigit_pos)
{
    map<int, int> digits_mp;
    bool foundSameDigit = false;

    for (int i=numOfDigits-1; i>=0 && prime > 0; i--)
    {
        digits_mp[prime%10] += 1;
        digit_v[i] = prime%10;   // save all digits of the prime
        prime /= 10; 
    }
    
    map<int, int>::iterator iter = digits_mp.begin();
    for(;iter!=digits_mp.end();iter++)
    {
        if (digits_mp[iter->first] >= numOfSameDigits) // found all same digits 
        {
            foundSameDigit = true;
            sameDigit = iter->first;
            break;
        }
    }

    // 2-digit: *Z
    // 5-digit: XY**Z
    // 6-digit: *X*Y*Z
    for(int i=numOfDigits-1, j=numOfSameDigits-1; i>=0 && j>=0; i--)  
    {
        if (digit_v[i] == sameDigit)
        {
            sameDigit_pos[j] = i;  // save same digit position
            j--;
        }
    }

    if (sameDigit_pos[numOfSameDigits-1] == numOfDigits-1)
    {
        foundSameDigit = false; // last digit can not be position of same digit
    }

    return foundSameDigit;
}

bool PE0051::checkPosInVector(int pos, vector<int> pos_vec)
{
    vector<int>::iterator pos_vec_iter = pos_vec.begin();

    for( ;pos_vec_iter != pos_vec.end(); pos_vec_iter++)
    {
        if (pos == *pos_vec_iter)
        {
            return true;
        }
    }
    return false;
}

int PE0051::getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits, 
                                   int numOfPrimes)
{
    vector<int> digitsVec(numOfDigits);            // all digits of prime
    vector<int> sameDigitsPosVec(numOfSameDigits); // same digits pos of prime
    int sameDigit = 0;

     // 2-digit: [10, 99], 5-digit: [ 10000, 99999], 6-digit: [100000...999999]
    int range_start = (int)pow(10.0, numOfDigits-1);
    int range_end   = (int)pow(10.0, numOfDigits) - 1;

    set<int> primes_set;
    set<int>::iterator ps_iter;

    for (int n=range_start; n<=range_end; n++) 
    {
        if (true == checkPrime(n))
        {
            primes_set.insert(n);

            if (true == getDigitsOfPrime(n, numOfDigits, numOfSameDigits, 
                                       digitsVec, sameDigit, sameDigitsPosVec))   
            {
                for (int i=sameDigit+1; i<=9; i++)
                {
                    int number = 0;

                    for(int j=0;j<numOfDigits;j++)
                    {
                        number *= 10;
                        if (true == checkPosInVector(j, sameDigitsPosVec))
                        {
                            number += i;
                        }
                        else
                        {
                            number += digitsVec[j];
                        }
                    }

                    if (true == checkPrime(number))
                    {
                        primes_set.insert(number); 
                    }
                }

                if (primes_set.size() == numOfPrimes)
                {
                    ps_iter = primes_set.begin();
#ifdef UNIT_TEST
                    copy(primes_set.begin(), primes_set.end(), 
                         ostream_iterator<int>(cout, "\t"));
                    cout << endl;
#endif
                    return *ps_iter;  // first prime in primes set
                }
            }

            primes_set.clear();
        }
    }

    return 0; 
}
    

int main()
{
    PE0051 pe0051;

    assert (13    == pe0051.getXdigitSmallestPrime(2, 1, 6));
    assert (56003 == pe0051.getXdigitSmallestPrime(5, 2, 7));

    cout << "8-digit first smallest prime is ";
    cout << pe0051.getXdigitSmallestPrime(6, 3, 8) << endl;

    return 0;
}

C++11 代码

#include <iostream>
#include <string>
#include <set>
#include <map>
#include <iterator>
#include <cmath>
#include <cassert>

using namespace std;

//#define UNIT_TEST

class PE0051
{
private:
    bool checkPrime(int number);
    int getSameDigitOfPrime(int prime, int numOfDigits, int numOfSameDigits);
    int replaceAllSameDigits(string s, int sameDigit, int newDigit);

public:
    int getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits, 
                               int numOfPrimes);
};

bool PE0051::checkPrime(int number)
{
    long double squareRoot = sqrt((long 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;
}

int PE0051::getSameDigitOfPrime(int prime, int numOfDigits, int numOfSameDigits)
{
    map<int, int> digits_mp;
    int sameDigit = 0;

    for (int i = numOfDigits - 1; i >= 0 && prime > 0; i--)
    {
        digits_mp[prime % 10] += 1;
        prime /= 10;
    }

    map<int, int>::iterator iter = digits_mp.begin();
    for (; iter != digits_mp.end(); iter++)
    {
        if (digits_mp[iter->first] == numOfSameDigits)  
        {
            sameDigit = iter->first;  // found same digit
            break;
        }
    }

    return sameDigit;
}

int PE0051::replaceAllSameDigits(string s, int sameDigit, int newDigit)
{
    for (unsigned int i=0; i<s.size(); i++)
    {
        if (s[i] == (char)('0'+sameDigit))
        {
            s[i] = (char)('0'+ newDigit);
        }
    }
    return stoi(s);
}

int PE0051::getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits,
                                   int numOfPrimes)
{
    // 2-digit: [10, 99], 5-digit: [ 10000, 99999], 6-digit: [100000...999999]
    int range_start = (int)pow(10.0, numOfDigits - 1);
    int range_end   = (int)pow(10.0, numOfDigits) - 1;

    set<int> primes_set;

    for (int n = range_start; n <= range_end; n++)
    {
        if (true == checkPrime(n))
        {
            primes_set.insert(n);

            int sameDigit = getSameDigitOfPrime(n, numOfDigits, numOfSameDigits);

            string digitsStr = to_string(n);

            for (int newDigit = sameDigit + 1; newDigit <= 9; newDigit++)
            {
                int number = replaceAllSameDigits(digitsStr, sameDigit, newDigit);

                if (true == checkPrime(number))
                {
                    primes_set.insert(number);
                }
            }

            if (primes_set.size() == numOfPrimes)
            {
#ifdef UNIT_TEST
                copy(primes_set.begin(), primes_set.end(), 
                     ostream_iterator<int>(cout, " "));
                cout << endl;
#endif
                return n;  // n is the first prime in primes set
            }
            primes_set.clear();
        }
    }

    return 0;
}
    
int main()
{
    PE0051 pe0051;

    assert(   13 == pe0051.getXdigitSmallestPrime(2, 1, 6));
    assert(56003 == pe0051.getXdigitSmallestPrime(5, 2, 7));

    int prime = pe0051.getXdigitSmallestPrime(6, 3, 8);
    cout << "8-digit first smallest prime is " << prime << "." << endl;

    return 0;
}

Python 代码

import re

def checkPrime(n):
    """
    check whether n is a prime
    """
    if n < 2 or n != 2 and n%2 == 0:
        return False

    for i in range(3, int(n**0.5)+1, 2):
        if 0 == n % i:
            return False
    
    return True

def getDigitsOfPrime(prime):
    """
    covert a prime to digits list
    """
    return [ int(digit) for digit in sorted(list(str(prime))) ]

def getXdigitSmallestPrime(numOfDigits, numOfPrimes):
    """
    get smallest prime with such property
    """
    for n in range(10**(numOfDigits-1), 10**numOfDigits):
        primes_list = []
        if True == checkPrime(n):
            primes_list.append(n)
            digits_list = getDigitsOfPrime(n)
            same_digit  = digits_list[0]
            s = str(n)
            for i in range(same_digit+1, 10):
                strinfo = re.compile(str(same_digit))
                ns = strinfo.sub(str(i), s)
                number = int(ns)
                if True == checkPrime(number):
                    primes_list.append(number)

        if numOfPrimes == len(primes_list):
            #print(primes_list)
            return primes_list[0]
        else:
            primes_list.clear()

    return 0

def main():
    assert    13 == getXdigitSmallestPrime(2, 6)
    assert 56003 == getXdigitSmallestPrime(5, 7)

    print("8-digit first smallest prime is",getXdigitSmallestPrime(6, 8))
    
if  __name__ == '__main__':
    main()
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值