베르트랑 공준은 임의의 자연수 n에 대하여, n보다 크고, 2n보다 작거나 같은 소수는 적어도 하나 존재한다는 내용을 담고 있다.
이 명제는 조제프 베르트랑이 1845년에 추측했고, 파프누티 체비쇼프가 1850년에 증명했다.
예를 들어, 10보다 크고, 20보다 작거나 같은 소수는 4개가 있다. (11, 13, 17, 19) 또, 14보다 크고, 28보다 작거나 같은 소수는 3개가 있다. (17,19, 23)
자연수 n이 주어졌을 때, n보다 크고, 2n보다 작거나 같은 소수의 개수를 구하는 프로그램을 작성하시오.
입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 케이스는 n을 포함하는 한 줄로 이루어져 있다.
입력의 마지막에는 0이 주어진다.
각 테스트 케이스에 대해서, n보다 크고, 2n보다 작거나 같은 소수의 개수를 출력한다.
1 ≤ n ≤ 123,456
✅ 문제 자체는 복잡해보지만 결국 핵심은
n+1 ~ 2n
사이의 소수를 찾는 문제였다! 소수를 찾는 알고리즘은 역시 이전 문제들과 동일한 코드를 사용하였는데, 아래 코드를 사용하면 정답 처리는 되지만 다른 사람들의 풀이에 비해 시간이 거의 3배정도 더 소요된다,,
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
while(true) {
int n = Integer.parseInt(br.readLine());
if(n == 0) break;
int cnt = 0;
for(int i=n+1;i<=2*n;i++) {
boolean isPrime = true;
for(int j=2;j<=Math.sqrt(i);j++) {
if(i % j == 0) {
isPrime = false; break;
}
}
if(isPrime) cnt++;
}
sb.append(cnt + "\n");
}
bw.write(sb + "");
br.close();
bw.close();
}
}
➕ 다른 사람의 풀이 : 이전 문제들부터 시간이 짧은 다른 사람들의 풀이를 보면 에라토스테네스의 체를 사용한 코드가 많았다. 에라토스테네스의 체란 소수를 구하는 대표적인 방법 중 하나로,
n+1 ~ 2n
사이의 소수를 구한다고 한다면n+1
부터√2n
까지 반복하여 2n을 제외한 2n의 배수들을 제외시키는 방법이다. 자세한 설명은 이 글을 참고하면 된다!
메서드getPrime()
은 주어진 범위에서 소수와 합성수를 구분하는 메서드이다. 해당 문제의 경우n
이 최대123,456
이므로2n
은 최대246,912
이 된다. 배열이 0부터 시작하므로 총 배열의 길이를246,913
으로 선언해주고,246,912
까지의 수 중 소수가 아닌n+1 ~ √2n
의 배수들의 요소에true
를 저장한다. 즉, 소수는 boolean 타입의 기본값인false
를 가지게 되는 것이다. 이렇게 주어진 범위 내에서 소수 판별 범위를 한 번만 수행한 후, 입력받은 데이터에 대해 값이false
인 요소만 카운트해주면 된다!
아래 코드를 제출하면 위 코드보다 시간이 거의 1/4배로 줄어든다!,,
import java.io.*;
import java.util.*;
public class Main {
static boolean[] prime = new boolean[246913];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
getPrime();
while(true) {
int n = Integer.parseInt(br.readLine());
if(n == 0) break;
int cnt = 0;
for(int i=n+1;i<=2*n;i++) {
if(!prime[i]) cnt++;
}
sb.append(cnt).append("\n");
}
bw.write(sb + "");
br.close();
bw.close();
}
static void getPrime() {
prime[0] = prime[1] = true;
for(int i=2;i<=Math.sqrt(prime.length);i++) {
if(prime[i]) continue;
for(int j=i*i;j<prime.length;j+=i) {
prime[j] = true;
}
}
}
}