공부/백준

2581번: 소수(백준 C++)

상연 2020. 10. 14. 15:02

목차

    소수

    문제

    자연수 M과 N이 주어질 때 M이상 N이하의 자연수 중 소수인 것을 모두 골라 이들 소수의 합과 최솟값을 찾는 프로그램을 작성하시오.
    예를 들어 M=60, N=100인 경우 60이상 100이하의 자연수 중 소수는 61, 67, 71, 73, 79, 83, 89, 97 총 8개가 있으므로, 이들 소수의 합은 620이고, 최솟값은 61이 된다.

    입력

    입력의 첫째 줄에 M이, 둘째 줄에 N이 주어진다.
    M과 N은 10,000이하의 자연수이며, M은 N보다 작거나 같다.

    출력

    M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다.
    단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.

    예제 입출력1

    입력
    60
    100

    출력
    620
    61

    예제 입출력2

    입력
    64
    65

    출력
    -1


    코드

    #include <iostream>
    #include <cmath>
    #include <vector>
    using namespace std;
    
    // 소수를 판별하는 함수, 소수라면 1을, 소수가 아니라면 0을 return한다.
    int judge_prime(int n){
      if(n == 1) return 0;
    
      for(int i=2; i <= sqrt(n); i++)
        if(n%i == 0) return 0;
    
      return 1;}
    
    int main(){
      int n1, n2; //소수판별할 범위의 시작과 끝, n1~n2
      int sum = 0; //범위 내 소수의 합
      int min = 10001;// 범위 내 소수의 최소값.
      bool arr[10001] = {0,}; // 1~10000까지의 배열, 배열의 값이 0이면 소수이고, 1이면 소수가 아니다.
    
      cin >> n1 >> n2; //범위 설정
    
      for(int i=n1; i <=n2; i++){
        // 배열의 값이 1-> 소수가 아니므로 다음값으로 바로 간다.
        if(arr[i] == 1) continue;
    
        // 소수라면?
        if(judge_prime(i)){
          // sum에 값을 추가하고, 최소를 판별하여 넣는다.
          sum += i;
          min = i < min ? i : min;
    
          //소수의 배수는 소수가 아니다. 그러므로 소수의 배수는 배열의 값을 1로 바꿔주어 판별하지 않는다.
          for(int j=1; i*j<=10000; j++ ){
            arr[i*j] = 1;
          }
        }
      }
     // 값 출력.
      if(sum)
        cout << sum << "\n" << min;
      else
        cout << -1;
    }
    

    사견이자 해석

    어제 풀었던 1978번과 유사하다. 다만 이번에는 연속적인 수의 나열에서 소수를 찾아내는 문제이다.

    따라서 가장 작은 수부터 탐색을 시작해서 소수인지 아닌지 판별을 한다.

    소수 판별 함수

    // 소수를 판별하는 함수, 소수라면 1을, 소수가 아니라면 0을 return한다.
    int judge_prime(int n){
      if(n == 1) return 0;
    
      for(int i=2; i <= sqrt(n); i++)
        if(n%i == 0) return 0;
    
      return 1;}

    위 함수의 Return 값이 1, 즉 소수라면
    그 수의 배수들은 소수가 아니라는 뜻이다. 그렇기 때문에 미리 판별 대상에서 제외를 해 주는 작업을 한다.

       //소수의 배수는 소수가 아니다. 그러므로 소수의 배수는 배열의 값을 1로 바꿔주어 판별하지 않는다.
          for(int j=1; i*j<=10000; j++ ){
            arr[i*j] = 1;
          }

    이렇게 하면, 판별해야할 대상들은 반복문이 반복될수록 적어지면서 값 도출의 시간을 줄일 수 있다.