Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 구현하는 피어폰트 소수(Pierpont Prime) 찾기


이 문제에서는 하나의 수 n이 주어지며, 우리의 목표는 n보다 작은 모든 피어폰트 소수(Pierpont Prime)를 찾아 출력하는 것입니다.

피어폰트 소수란 다음과 같은 특정한 형태를 갖는 소수를 의미합니다.

p = 2i × 3k + 1

여기서 p는 소수이며, i와 k는 임의의 음이 아닌 정수입니다. 쉽게 말해, 어떤 수에서 1을 뺀 값이 오직 2와 3의 거듭제곱의 곱으로만 표현될 수 있고, 그 수 자체가 소수라면 그것이 바로 피어폰트 소수입니다.

문제를 이해하기 위해 예시를 살펴보겠습니다.

입력 − n = 50

출력 − 2, 3, 5, 7, 13, 17, 19, 37

예를 들어 13은 13 − 1 = 12 = 22 × 31이므로 피어폰트 소수입니다. 반면 11은 11 − 1 = 10 = 2 × 5로, 5라는 다른 소인수가 포함되어 있어 피어폰트 소수에 해당하지 않습니다.

접근 방법

이 문제를 해결하려면 주어진 형태 조건을 만족하는 모든 수를 생성한 뒤, 그중에서 실제로 소수인 것만 골라내야 합니다. 전체 알고리즘은 다음과 같이 정리할 수 있습니다.

  1. 2의 거듭제곱과 3의 거듭제곱을 조합하여(2i × 3k) n 미만의 모든 값을 구합니다.
  2. 각 값에 1을 더한 수를 피어폰트 소수 후보 목록에 저장합니다.
  3. 에라토스테네스의 체를 이용해 각 후보가 소수인지 판별합니다.
  4. 후보 목록 중 소수에 해당하는 값만 순서대로 출력합니다.

예제 코드

위에서 설명한 풀이를 C++로 구현한 프로그램은 다음과 같습니다.

#include <bits/stdc++.h>
using namespace std;
void printPierpontPrimes(int n){
   bool arr[n+1];
   memset(arr, false, sizeof arr);
   int two = 1, three = 1;
   while (two + 1 < n) {
      arr[two] = true;
      while (two * three + 1 < n) {
         arr[three] = true;
         arr[two * three] = true;
         three *= 3;
      }
      three = 1;
      two *= 2;
   }
   vector<int> primes;
   for (int i = 0; i < n; i++)
   if (arr[i])
      primes.push_back(i + 1);
   memset(arr, false, sizeof arr);
   for (int p = 2; p * p < n; p++) {
      if (arr[p] == false)
         for (int i = p * 2; i< n; i += p)
            arr[i] = true;
   }
   for (int i = 0; i < primes.size(); i++)
      if (!arr[primes[i]])
      cout<<primes[i]<<"\t";
}
int main(){
   int n = 50;
   cout<<"All Pierpont Prime Numbers less than "<<n<<" are :\n";
   printPierpontPrimes(n);
   return 0;
}

실행 결과

All Pierpont Prime Numbers less than 50 are :
2    3    5    7    13    17    19    37

n = 50일 때 50 미만의 피어폰트 소수는 총 8개로, 2, 3, 5, 7, 13, 17, 19, 37임을 확인할 수 있습니다. 이처럼 2와 3의 거듭제곱 조합으로 후보를 먼저 생성하고, 소수 판별을 통해 최종 결과를 얻는 방식은 불필요한 연산을 줄여 효율적으로 문제를 해결할 수 있습니다.