[BOJ] 2581번 소수
소수 << 문제 클릭!
✅문제 설명
- 입력 : 자연수 M, N (M, N은 10,000 이하의 자연수, M은 N보다 작거나 같다)
- 자연수 M이상 N 이하의 자연수 중 소수를 모두 찾는다.
- 소수의 합과 최솟값을 찾는다.
- 출력
: 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력
: M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.
❗핵심원리
-
소수 찾기
: 주어진 M 이상에서 소수를 찾는 방법은 없을까?
-> 없음 소수는 자기 자신과 1로만 나누어지는 수 이므로 1부터 자기자신까지 나누어서 소수를 찾아야 한다.
-> 그렇다면 더 빨리 소수를 찾는 방법은?
-> 소인수분해를 했을 때 1과 자기자신의 곱으로 분해되면 소수로 판단한다.✅ 소수를 따로 저장하고 소수 판별에 사용하자
💻코드
1차 문제 풀이
- 1부터 M까지 소수를 구하고 M부터 N까지 소수를 찾고 더해주는 전략
- 이때 소수를 vector s에 담고 소수 판별할 때 활용한다.
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
ios::sync_with_stdio(0); // C 표준 stream과 C++ 표준 stream의 동기화를 끊는다.
cin.tie(0);
int M, N;
int min = 0;
int sum = 0;
vector<int> s; // 소수만 담겨있다.
cin >> M >> N;
s.push_back(2); // 2가 소수임을 알고 있는 가정 하에
for (int i = 3; i < M; i++) {
// M 전까지 소수 담기
int j = 0;
for (; j < s.size(); j++) {
if (i % s[j] == 0) break; // 소수 중 하나라도 나줘지면 기각
}
if (j == s.size()) s.push_back(i); // 소수 추가
}
for (int i = M; i < N + 1; i++) {
int j = 0;
for (; j < s.size(); j++) {
if (i % s[j] == 0) break; // 소수 중 하나라도 나줘지면 기각
}
if (j == s.size()) {
s.push_back(i);
if (sum == 0) min = i; // 최솟값
sum += i; // 합을 더해줌
}
}
if (sum == 0) {
cout << -1;
}
else {
cout << sum << "\n" << min;
}
}
- 1차 위기 : 반례 2, 2를 -1로 출력, 그래서 N이 2일 때 2 2를 출력 후 종료
- 2차 위기 : 반례 1, 1을 1 1로 출력하려고 했으나 더 이상 코드가 효율적이지 못 하다는 판단 하에 뜯어 고치기로 함.
2차 문제 풀이
- 그냥 1부터 N까지 소수를 찾는다.
- 이때 소수를 vector s에 담고 소수 판별할 때 활용한다.
- 그리고 M보다 큰 소수에 대해 sum을 한다.
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
int M, N = 0;
int min = 0;
int sum = 0;
cin >> M >> N;
vector<int> s; // 소수가 담겨있다.
s.push_back(2);
for (int i = 1; i < N + 1; i++) {
int j = 0;
for (; j < s.size(); j++) {
if (i % s[j] == 0 || i ==1) { // 1은 기각
if (i == 2) { // 나눠지는 수 중 2는 계속 진행시켜서 j++를 수행시킨다.
continue;
}
break;
}
}
if (j == s.size()) {
s.push_back(i);
if (i >= M) { // i가 M보다 클 때 더함
if (sum == 0) {
min = i;
}
sum += i;
}
}
}
if (sum == 0) {
cout << -1;
}
else {
cout << sum << "\n" << min;
}
}
다른 분의 문제 풀이 (클릭)
#include <iostream>
using namespace std;
int main()
{
int max, min;
int count = 0; // 나눠떨어지는 수의 갯수
int nCount = 0; // 소수 갯수
int result = 0, minNumber; // 합, 소수 최솟값
cin >> min;
cin >> max;
for (int i = min; i <= max; i++) // min부터 max에 대해서
{
for (int j = 1; j <= i; j++) // 1부터 자기자신까지 나눈다.
{
if (i % j == 0)
count++;
}
if (count == 2) / /소수인경우
{
nCount++; // 소수 개수 count
result += i; // 더함
if (nCount == 1) // 최쵤때
minNumber = i;
}
count = 0;
}
if (nCount == 0)
{
minNumber = -1;
cout << minNumber << endl;
}
else
{
cout << result << endl << minNumber << endl;
}
return 0;
}
- 즉 M부터 N을 i로 나누어 (i는 i=1~i = k [k = M, M+1, M+2 ,,,, N])까지 소수 판별
확실히 소수를 저장한 후 소수를 이용해 소수를 찾는 전략이 더 빠르다!
Author And Source
이 문제에 관하여([BOJ] 2581번 소수), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@juijeong8324/BOJ-2581번-소수저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)