Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기

Algorithm/D. Math & Number Theory

48. Prime Factorization

소인수분해(Prime Factorization)는 양의 정수를 소수들의 곱으로 나타내는 것으로 다양한 문제에서 등장하는 개념이다. 소인수분해를 하는 방법은 다양하고 응용 범위도 넓은 편이기 때문에 각각의 상황에 맞는 소인수분해 방법을 선택하는 것이 좋다.

 

가장 간단한 소인수분해 방법은 다음과 같다.

vector<int>v;
void f(int n)
{
    for(int i = 2; i <= n; i++)
    {
        while(n % i == 0)
        {
            v.push_back(i);
            n /= i;
        }
    }
}

2 이상 n 이하의 모든 정수를 확인하면서 ni의 배수이면 i를 소인수 목록에 추가하고 ni로 나눈 다음 계속 진행한다. 하지만 이 방법은 n1억 정도의 소수일 경우 성능이 상당히 떨어진다. 다행히도 위의 코드를 조금만 수정하면 성능은 매우 좋아진다.

vector<int>v;
void f(int n)
{
    for(int i = 2; i * i <= n; i++)
    {
        while(n % i == 0)
        {
            v.push_back(i);
            n /= i;
        }
    }
    if(n > 1)v.push_back(n);
}

두 코드에서 f 함수를 실행한 결과는 같지만, 성능은 두 번째 코드가 더 좋다. 두 번째 코드는 n1억 정도여도 바깥쪽 반복문은 최대 1만 번만 실행되므로 빠르게 소인수분해를 할 수 있다.

짝수 소수가 2밖에 없다는 점을 이용하면 조금 더 효율적인 코드를 작성할 수도 있다.

vector<int>v;
void f(int n)
{
    while(n % 2 == 0)
    {
        v.push_back(2);
        n /= 2;
    }
    for(int i = 3; i * i <= n; i += 2)
    {
        while(n % i == 0)
        {
            v.push_back(i);
            n /= i;
        }
    }
    if(n > 1)v.push_back(n);
}

세 번째 코드에서는 i2씩 증가하므로 실행 속도가 두 번째 코드보다 2배 정도 빠르다. 다만 대부분의 문제의 경우 세 번째 코드로 풀 수 있다면 두 번째 코드로도 풀 수 있으므로 효율성에 비해 많이 쓰이지는 않는 편이다.

 

여기서 설명한 소인수분해 방법은 n1015 이하라면 나름 괜찮은 성능을 보이지만 n이 그 이상으로 커지면 성능이 급격하게 떨어진다. 또한 n의 범위가 작지만 소인수분해를 해야 할 수가 여러 개인 경우 이 방법으로 각각의 수들을 소인수분해하는 것은 비효율적이라는 문제점도 존재한다. 이 두 가지 문제점을 해결하는 방법이 각각 존재한다. 여러 개의 수를 소인수분해할 때는 에라토스테네스의 체를 이용할 수 있다. 수의 범위가 큰 경우에는 폴라드 로를 이용하면 된다. 폴라드 로에 대한 글은 추후 작성할 예정이다.

 

[연습문제]

 

BOJ 11653. 소인수분해 (Silver IV)

더보기

앞에서 설명한 대로 소인수분해를 하면 된다.

 

→ solved.ac tag: primality_test

'Algorithm > D. Math & Number Theory' 카테고리의 다른 글

50. Pigeonhole Principle  (0) 2021.06.02
49. Sieve of Eratosthenes  (0) 2021.05.30
47. Probability  (0) 2021.05.16
46. Combinatorics  (0) 2021.05.15
45. Modular Operation  (0) 2021.05.12