[정수론] 소수

Jewook·2022년 7월 20일

알고리즘

목록 보기
1/14

에라토스테네스의 체

vector<bool> isPrime(N+1, true);
isPrime[0] = isPrime[1] = false;
for (int i=2; i<= sqrt(N); ++i) {
	if (isPrime[i]) {
    	for (int temp = i*i; temp<=N; temp+= i)
        	isPrime[temp] = false;
    }
}

중요한 포인트가 두개 있다. sqrt(n)까지만 탐색하는 것과, 소수 p를 발견하고 n까지 p의 배수들을 지울 때, p*p부터 시작한다는 점이다.

sqrt(n)까지만 봐도 되는 이유는, isPrime의 기본값이 true이기 때문이다. 따라서 우리는 합성수들에 대해 isPrime의 값을 전부 false로 처리했다고 보장할 수 있으면 탐색을 종료하는 최적화가 가능하다.
sqrt(n)보다 크고 N이하인 합성수들은 sqrt(n)보다 작은 소인수를 반드시 가진다. 따라서 이미 sqrt(n) 이전의 소수에 의해 합성수로 처리되었음을 보장할 수 있다.

또한 소수 p에 대해서, p보다 작은 소수들의 배수들은 이미 지워졌기 때문에, p*2가 아니라 p*p부터 탐색하면 된다.


소인수 분해

vector<int> primeFactorization(int n) {
	vector<int> ret;
    for (int i=2; i<=sqrt(n); ++i) {
    	while (n%i==0) {
        	ret.push_back(i);
            n/=i;
       	}
    }
    if (n >1)
    	ret.push_back(n);
    return ret;
}

i가 소수인지 합성수인지 체크할 필요가 없다. i가 합성수라면, i의 소인수들은 i보다 작으므로 이미 n에서 나눠졌기 때문에 while문이 실행되지 않는다. 그리고 sqrt(n)까지만 탐색했는데, sqrt(n)보다 큰 소인수는 기껏해야 하나만 존재함을 귀류법으로 쉽게 증명할 수 있고, 그 소인수는 남아있는 n임을 알 수 있다.

위 알고리즘을 에라토스테네스의 체로 전처리를 하면, 소수들만 탐색하도록 최적화할 수 있다.


소수 판별

bool isPrime(int n) {
	if (n<=2) {
    	// 따로 처리
    }
    if (n%2==0)
    	return false;
    for (int i=3; i<=sqrt(n); ++i) 
    	if (n%i == 0)
        	return false;
    return true;
}

마찬가지로 에라토스테네스의 체를 이용하면 최적화할 수 있다.


소인수 분해 (최적화버전)


//isPrime 대신 다른방식으로 소수를 판별한다
//[i] : i의 소인수중 가장 작은 소인수
//[i] = i로 초기화해두고, [i] == i면 소수로 판단
int minFactor[N+1];
minFactor[1] = -1; // 예외

// 에라토스테네스의 체 전처리
for (int i=2; i<= sqrt(N); ++i) {
	if (minFactor[i] == i) {
    	for (int temp = i*i; temp<=N; temp+= i)
        	if (minFactor[temp] = temp)
            	minFactor[temp] = i;
    }
}

vector<int> optimizedPrimeFactorization(int n) {
	vector<int> ret;
    while (n>1) {
    	ret.push_back(minFactor[n]);
        n /= minFactor[n];
    }
}

흥미롭다.

참고 ) 종만북

profile
https://solved.ac/profile/huh0918

0개의 댓글