Algorithm/baekjoon
[BOJ 4948]베르트랑 공준
식빵민
2022. 7. 30. 18:24
4948번: 베르트랑 공준
베르트랑 공준은 임의의 자연수 n에 대하여, n보다 크고, 2n보다 작거나 같은 소수는 적어도 하나 존재한다는 내용을 담고 있다. 이 명제는 조제프 베르트랑이 1845년에 추측했고, 파프누티 체비쇼
www.acmicpc.net
문제 분석
- 제한시간 1초 : Big-O 기준 최대 1억 연산
- 1 ≤ n ≤ 123,456
- n 부터 2n 까지 소수인걸 센다.
계획
- bool형 배열을 만들어 2n까지의 수들 중 소수가 아닌 index의 값을 false로
- 이때, 에라토스테네스의 체를 이용한다.
(에라토스테네스란 2부터 어떤수 까지 자기자신을 제외한 배수를 거름으로써 소수를 구하는 것을 말한다.) - i의 배수를 지울때 "i*i" 부터 지우면 된다."i*j" (j<i) 는 i-j의 배수를 지울때 이미 지움
➣ 이로 인하여 √(2n) 의 배수까지만 지우면 된다.
#include <iostream>
#include <cmath>
#define MAX 250000
int n,last, cnt;
bool arr[MAX];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
do{ // n이 0으로 초기화 되어있으므로 한번은 해준다.
cin>>n;
last = 2*n; //2n까지 시행
cnt = 0;
if(n==0) return 0;
for (int i = n; i <= last; i++) {
arr[i] = true;
}// 모든 값을 true로 초기화
for(int i=2;i<=sqrt(last);i++){ //2부터 root(last)까지의 배수
for(int j=i;i*j<=last;j++){ // 곱해서 last넘어가면 안해도 됨
arr[i*j] = false; //i의 제곱부터 i의 배수 false로
}
}
for (int i = n+1; i <= last; i++) {
if (arr[i]) {
cnt++;
}
}
cout<<cnt<<"\n";
}while(n!=0);
}
느낀 점
- 처음엔 <map>을 이용한 재귀함수를 사용했다. 그랬더니 시간초과가 떴다. (<map>에서 index접근은 상수시간을 보장하지 않기 때문이다.)
- 그래서 배열을 만들었고, 재귀함수를 이중반복문 형태로 바꿔서 구현했다. 재귀함수에서는 반복문에서 한번, 반복문을 벗어나서 한번 함수를 호출해주기 때문에 시간이 더 걸리는 것 같다.
시간 복잡도(테스트 케이스 하나당)
- 이중 반복문 -> O(n²)