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

C++로 거의 완전수(Almost Perfect Number) 판별하기


거의 완전수(Almost Perfect Number)는 '최소 결핍수(least deficient number)' 또는 '약간 결핍수(slightly defective number)'라고도 불리며, 1과 자기 자신을 포함한 모든 약수의 합이 2n-1과 정확히 일치하는 수를 의미합니다.

일반적인 완전수(perfect number)가 약수의 합이 2n과 같은 수라면, 거의 완전수는 그 값에서 정확히 1이 작은 경우입니다. 이 글에서는 주어진 수가 거의 완전수인지 판별하는 알고리즘을 C++ 코드와 함께 살펴보겠습니다.

개념 이해를 위한 예시

입력 : 16
출력 : YES
설명 :
16의 약수는 1, 2, 4, 8, 16입니다.
약수의 합 = 1 + 2 + 4 + 8 + 16 = 31
n = 16 ; 2n-1 = 2 × 16 - 1 = 31

입력 : 12
출력 : NO
설명 :
12의 약수는 1, 2, 3, 4, 6, 12입니다.
약수의 합 = 1 + 2 + 3 + 4 + 6 + 12 = 28
n = 12 ; 2n-1 = 2 × 12 - 1 = 23

위 예시에서 볼 수 있듯이, 16의 약수 합(31)은 2×16-1과 정확히 일치하므로 거의 완전수에 해당하지만, 12의 약수 합(28)은 2×12-1인 23과 다르므로 거의 완전수가 아닙니다.

참고로, 현재까지 알려진 거의 완전수는 모두 2의 거듭제곱(1, 2, 4, 8, 16, ...)뿐이며, 이 외의 거의 완전수가 존재하는지는 아직 밝혀지지 않았습니다.

알고리즘

주어진 수가 거의 완전수인지 판별하는 절차는 다음과 같습니다.

  1. 입력받은 수 n의 모든 약수의 합(sum)을 계산합니다.
  2. 비교 기준값 val = 2n - 1을 계산합니다.
  3. sum == val이면 "YES"를 출력합니다.
  4. 그렇지 않으면 "NO"를 출력합니다.

C++ 구현 코드

#include <iostream>
using namespace std;

// 거의 완전수 여부를 판별하는 함수
void almostPerfectNumber(int n);

int main() {
    int n = 16;
    cout<<n<<" 은(는) 거의 완전수인가요?\n";
    almostPerfectNumber(n);
}

void almostPerfectNumber(int n) {
    int divisors = 0;   // 약수의 합을 저장할 변수

    // 1부터 n까지 반복하며 약수를 찾아 합산
    for (int i = 1; i <= n; i++) {
        if (n % i == 0)
            divisors += i;
    }

    // 약수의 합이 2n - 1과 같은지 비교
    if (divisors == 2 * n - 1)
        cout<<"YES";
    else
        cout<<"NO";
}

실행 결과

16 은(는) 거의 완전수인가요?
YES

코드 동작 원리 및 성능

이 코드는 1부터 n까지 모든 수를 직접 나누어 떨어지는지 확인하는 방식으로 약수를 찾습니다. 시간 복잡도는 O(n)이며, 약수는 쌍으로 존재한다는 성질을 활용해 √n까지만 검사하면 O(√n)으로 최적화할 수 있습니다. 큰 수를 다룰 때는 후자의 방식이 훨씬 효율적입니다.