소수(Prime number)는 약수가 1과 자기 자신뿐인 수를 말합니다. 소수의 반대말은 합성수(Composite number)겠죠?
1보다 큰 모든 정수는 소수거나 합성수입니다.
어떤 수 N이 소수인지 아닌지 판별하는 방법
N을 2부터 N-1까지의 수로 나눴을 때 나머지가 0이 나오면 합성수고, 아니면 소수입니다.
bool prime(int n) {
if (n<2)
return false;
for (int i=2; i*i<=n; ++i)
if (n%i == 0)
return false;
return true;
}
그걸 코드로 옮기면 이렇게 되는데요, 중간에 \(i*i \leq n\)이 들어가 있는데 \(i \leq \sqrt{n}\)을 실수 연산을 피하기 위해 \(i*i\)를 사용했습니다.
약수를 확인할 때는 \(n-1\)까지 확인하는 대신, \(\sqrt{n}\)까지만 확인하면 됩니다.
시간복잡도는 \(O( \sqrt{n} ) \)입니다.
에라토스테네스의 체
2부터 N까지 범위 안의 모든 소수를 구하려면 에라토스테네스의 체(Sieve of Eratosthenes)를 사용합니다.
알고리즘은 굉장히 간단합니다.
- 2부터 N까지 모든 수를 쓴다
- 지워지지 않은 수 중에서 가장 작은 수를 찾는다.
- 그 수는 소수이다
- 그 수의 배수를 모두 지운다
int prime[50]; // 소수를 저장하는 배열
int pn = 0; // 소수의 갯수
bool erased[101]; // 지워졌으면 true
int n = 100; // 100까지의 소수 구하기
for (int i=2; i<=n; ++i) {
if (!erased[i]) {
prime[pn++] = i;
for (int j=i*2; j<=n; j+=i)
erased[j] = true;
}
}
숫자를 지우는 작업은 인덱스를 체크하는 것으로 하고, 소수는 따로 뽑아서 순서대로 저장해 놓습니다.
제일 안쪽 for문에서 j=i*2로 시작했지만, 사실은 i*i로 하면 이미 없앤 수를 많이 건너뛸 수 있습니다.
예를 들어 5의 배수를 지울 때를 생각하면 5*2, 5*3, 5*4, 5*5, ...의 순으로 지울 겁니다. 하지만 앞의 5*2, 5*3, 5*4 까지는 이미 앞선 2, 3의 배수를 지울 때 지워졌기 때문에 5*5부터 지워나가면 됩니다.
하지만 i*i는 오버플로우의 위험이 있으니 i값이 커진다면 i*2를 사용해야 합니다.
반응형
'수학 > 정수론' 카테고리의 다른 글
약수의 개수, 약수의 합 (0) | 2020.07.03 |
---|---|
음수의 모듈러 연산 (0) | 2020.04.09 |
최대공약수(GCD)와 최소공배수(LCM) (0) | 2020.04.09 |
큰 수의 모듈러 연산 (0) | 2020.03.24 |