에라토스테네스의 체 (Sieve of Eratosthenes)
정의
에라토스테네스의 체 (Sieve of Eratosthenes) 는 1부터 N 까지의 모든 소수를 O(N log log N) 에 찾는 고대 그리스 알고리즘. 기원전 240 년경 에라토스테네스가 고안. 선형 체 (Linear Sieve) 는 개선 버전으로 O(N) 에 모든 소수 + 최소 소인수 (SPF) 를 구한다.
문제 상황과 동기
N 이하의 모든 소수를 나열하라.
- naive: 각 수마다 소수 판정 O(√N) → 총 O(N√N). N=10^7 이면 10^10 연산.
- 에라토스테네스: 2 의 배수 지우기, 3 의 배수 지우기, … O(N log log N). N=10^7 도 0.1 초.
- 선형 체: 각 합성수를 최소 소인수로 정확히 한 번만 지움. O(N).
핵심 통찰: “소수 p 의 배수는 모두 합성수”. 작은 소수부터 배수를 지워 나가면 남은 수가 소수. 선형 체는 “각 합성수를 SPF 로만 지움” 으로 중복 제거.
자주 등장: 소인수분해, 오일러 φ, 뫼비우스 함수, 수론 DP (예: 약수 DP), 골드바흐 추측 검증.
시각화
핵심 아이디어
에라토스테네스 체
초기: is_prime[2..N] = true
for p = 2..√N:
if is_prime[p]:
for k = p^2, p^2 + p, ..., N:
is_prime[k] = false
p^2 부터 시작: p * (p-1), p * (p-2), … 는 이미 더 작은 소수로 지워짐.
복잡도 분석: 각 소수 p 에 대해 N/p 번 지움. Σ (N/p) = N Σ (1/p) = N log log N (소수의 역수 합 → log log N).
선형 체 (Linear Sieve)
for i = 2..N:
if spf[i] == 0: # i 는 소수
primes.append(i)
spf[i] = i
for p in primes:
if i * p > N:
break
spf[i * p] = p
if i % p == 0:
break # i 의 최소 소인수 = p, i*p 는 나중에 다시 안 지움
invariant: 각 합성수 n 은 SPF(n) 로만 지워진다. i % p == 0 일 때 break → 더 큰 p 는 i 의 진짜 소인수가 아님 → 중복 방지 → O(N).
알고리즘
에라토스테네스 체
sieve(N):
is_prime[2..N] = true
for p = 2..√N:
if is_prime[p]:
for k = p^2, p^2 + p, ..., N:
is_prime[k] = false
return [i for i in 2..N if is_prime[i]]
선형 체
linear_sieve(N):
spf[2..N] = 0
primes = []
for i = 2..N:
if spf[i] == 0:
primes.append(i)
spf[i] = i
for p in primes:
if i * p > N:
break
spf[i * p] = p
if i % p == 0:
break
return primes, spf
구현
// 에라토스테네스 O(N log log N) + 선형 체 O(N)
#include <bits/stdc++.h>
using namespace std;
vector<int> sieve(int N) {
vector<bool> is_prime(N + 1, true);
is_prime[0] = is_prime[1] = false;
for (int p = 2; p * p <= N; p++) {
if (is_prime[p]) {
for (int k = p * p; k <= N; k += p)
is_prime[k] = false;
}
}
vector<int> primes;
for (int i = 2; i <= N; i++)
if (is_prime[i]) primes.push_back(i);
return primes;
}
pair<vector<int>, vector<int>> linear_sieve(int N) {
vector<int> spf(N + 1, 0), primes;
for (int i = 2; i <= N; i++) {
if (spf[i] == 0) {
primes.push_back(i);
spf[i] = i;
}
for (int p : primes) {
if (i * p > N) break;
spf[i * p] = p;
if (i % p == 0) break;
}
}
return {primes, spf};
}
int main() {
int N; cin >> N;
auto primes1 = sieve(N);
auto [primes2, spf] = linear_sieve(N);
cout << "Eratosthenes: " << primes1.size() << " primes\n";
cout << "Linear sieve: " << primes2.size() << " primes\n";
cout << "First 10: ";
for (int i = 0; i < min(10, (int)primes2.size()); i++)
cout << primes2[i] << " ";
cout << "\n";
}100Eratosthenes: 25 primes
Linear sieve: 25 primes
First 10: 2 3 5 7 11 13 17 19 23 29복잡도
| 항목 | 에라토스테네스 | 선형 체 |
|---|---|---|
| 시간 | O(N log log N) | O(N) |
| 공간 | O(N) | O(N) |
| 구현 난이도 | 쉬움 | 중간 |
에라토스테네스: N=10^7 일 때 ~0.05 초 (실전 충분). 선형 체: N=10^7 일 때 ~0.03 초. SPF 배열로 소인수분해도 O(log N).
변형 / 활용
1. 구간 체 (Segmented Sieve)
[L, R] (R-L ≤ 10^6, R ≤ 10^12) 의 소수 찾기. 작은 소수 (√R 이하) 만 미리 구함 → 구간 [L, R] 에서 배수 지움. O(√R + (R-L) log log R).
2. 소인수분해 O(log N)
선형 체로 SPF[n] 알면 n = SPF[n] · (n / SPF[n]) 재귀. log N 회.
vector<int> factorize(int n, const vector<int>& spf) {
vector<int> factors;
while (n > 1) {
factors.push_back(spf[n]);
n /= spf[n];
}
return factors;
}
3. 오일러 φ 함수
φ(n) = n · Π (1 - 1/p) (p: n 의 소인수). 선형 체로 모든 φ(1..N) 을 O(N) 에.
4. 뫼비우스 함수 μ(n)
μ(n) = (-1)^k (k: 서로 다른 소인수 개수), 제곱 인수 있으면 0. 포함-배제.
함정
1. 범위 시작
is_prime[0], is_prime[1] 을 false 로 초기화 안 하면 오답.
2. p^2 overflow
p * p 가 int 범위 넘으면 오버플로우. p * p > N 대신 p > sqrt(N) 또는 long long.
3. 선형 체 break 조건
if (i % p == 0) break 빼먹으면 O(N^2) 로 폭발. 핵심 invariant.
4. 메모리
N=10^8 이면 bool 배열 100MB. 비트셋으로 압축 가능.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 1929 | 소수 구하기 | - | kokoa-lab |
| BOJ 1016 | 제곱 ㄴㄴ 수 | - | kokoa-lab |
| BOJ 4948 | 베르트랑 공준 | - | kokoa-lab |
| BOJ 11653 | 소인수분해 | - | kokoa-lab |
참고
이 글의 용어 (4개)
- 소인수분해 (Prime Factorization)algorithm
- 정의 소인수분해 (Prime Factorization) 는 양의 정수 N을 소수들의 곱으로 유일하게 나타내는 것. N = p₁^a₁ · p₂^a₂ · ... · pₖ^aₖ. 시행…
- 정수론 (Number Theory)algorithm
- 정의 정수론 (Number Theory) 은 정수의 성질과 관계를 연구하는 분야. PS 에서는 약수/배수, 소수 (prime), 모듈러 연산, 유클리드 호제법, 확장 유클리드, …
- Euler Phi Function: φ(n)algorithm
- 정의 Euler Phi Function φ(n) 은 1 이상 n 이하 정수 중 n 과 서로소인 정수의 개수. 기존 Euler Phi 위키 참조. 이 페이지는 alias 확장용 축…
- Miller-Rabin 소수 판정 (Miller-Rabin Primality Test)algorithm
- 정의 Miller-Rabin 소수 판정 은 N 이 소수인지 확률적/결정론적으로 판별하는 알고리즘. Fermat 작은 정리와 이차잉여 성질을 결합해 O(k log^3 N) 에 동작…
💬 댓글