본문 바로가기

CodingTEST

[백준 2023] 신기한 소수 (JAVA)

반응형

백준 2023번 문제  - 신기한 소수

 

2023번: 신기한 소수

수빈이가 세상에서 가장 좋아하는 것은 소수이고, 취미는 소수를 가지고 노는 것이다. 요즘 수빈이가 가장 관심있어 하는 소수는 7331이다. 7331은 소수인데, 신기하게도 733도 소수이고, 73도 소수

www.acmicpc.net


문제 분석

 

  • 자리수가 입력되면 해당 자리 수 중에서 다음 조건을 만족하는 수(신기한 소수)들을 출력해라
    • N번자리부터 오른쪽으로 0부터 N-1까지 숫자를 같이 봤을 때 모든 수가 다 소수인 수
      ex) N = 4 | 주어진 숫자 = 2333 일 때 해당 수는 신기한 소수에 포함 (다음 표 참고)
i N부터 i까지 오른 쪽 숫자 소수 판별
0 2 O
1 23 O
2 233 O
3 2333 O

 


해결 키 포인트

 

  • DFS(깊이 우선 탐색) 개념 파악 : 사실 본 포스트 코드는 깊이 우선 탐색을 잘 사용하진 않음
  • 소수 개념 파악
    - 소수 : 해당 수가 1과 자기 자신으로만 나누어 떨어지는 수 (1은 미포함)
  • 속도를 줄이기 위해, i 자리 수까지의 수가 소수가 아닐 경우는 해당 자릿 수를 증가시켜 변경
    ex) 200 : 2 (소수 O) - 20 (소수 X) → 다음 확인할 수는 201이 아닌 210 !

깊이 우선 탐색(DFS)

 

그래프 완전 탐색 기번 중 하나로, 그래프의 시작 노드에서 출발하여 탐색할 한 쪽 분기를 정하여 최대 깊이까지 탐색을 마친 후 다른 쪽 분기로 이동하여 다시 탐색을 수행하는 알고리즘이다.

 

깊이 우선 탐색은 실제 구현 시 재귀 함수를 이용하므로 스택 오버플로에 유의해야 한다.

 

깊이 우선 탐색의 핵심 이론

 

  • 한번 방문한 노드를 다시 방문하면 안되므로 노드 방문 여부를 체크할 배열이 필요
  • 그래프는 인접 리스트로 표현
  • DFS의 탐색 방식은 후입 선출 특성을 가짐 ( 재귀함수 사용 많음 / 스택도 사용 )

 

알고리즘

1. DFS를 시작할 노드를 정한 후 사용할 자료구조 초기화

 

Do It! 알고리즘 코딩 테스트

 

2. 스택에서 노드를 꺼낸 후 꺼낸 노드의 인접 노드를 다시 스택에 삽입 (이를 모든 정점을 다한다)

 

Do It! 알고리즘 코딩 테스트

 

만약 스택에 노드가 없으면, 방문하지 않은 정점을 알아내, 스택에 삽입하고 다시 2번 단계를 반복한다.


코드
import java.io.*;

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));

        // N 입력
        int N = Integer.parseInt(br.readLine());
        br.close();

        // 해당 자리수의 가장 작은 값
        int minNum = 1;
        for (int i = 1; i < N; i++) {
            minNum *= 10;
        }
        // 해당 자리수의 가장 큰 값 다음 값
        int maxNum = minNum * 10;

        // 현재 수
        int currentNum = minNum;

        // max 수까지 반복
        while (currentNum < maxNum) {
            int[] Nnum = new int[N];
            Nnum[N - 1] = currentNum / minNum;

            // N번째 자리 수가 소수여야 함 (2,3,5,7)
            if (checkPrimeNumber(Nnum[N - 1])) {
                // 수가 두자리 이상일 경우
                if (N >= 2) {
                    int checkNum = minNum / 10;

                    int i = N-2;
                    // 각 자리 수의 값 알아내기
                    for (i=N-2; i>=0; i--) {
                            Nnum[i] = currentNum % (checkNum * 10) / (checkNum);
                            int num = currentNum / checkNum;

                        // 해당 자리 수까지 값이 소수인지 판별 | 아니라면 해당 수는 안되는 수이므로 해당 자리수 증가시켜 수 변경
                        if (!checkPrimeNumber(num)) {
                            currentNum = checkNum * (num + 1);
                            break;
                        }

                        // 해당 자리수까지 소수라면 다음 자리수 확인
                        checkNum /= 10;
                    }

                    // 지금 확인 자리수가 -1이면 해당 조건을 만족하는 소수이므로 출력 및 수 변경
                    if (i == -1) {
                        bw.write(currentNum + "\n");
                        currentNum++;
                    }

                // 한자리 수일 경우, 해당 수가 소수이면 소수이므로 출력
                } else {
                    bw.write(currentNum + "\n");
                    currentNum++;
                }

            }
            // N번째 자리 수가 소수가 아니라면 해당 자리수 숫자 변경
            else {
                currentNum = minNum * (Nnum[N - 1] + 1);
            }
        }

        // 출력
        bw.flush();
        bw.close();
    }

    // 소수인지 알아내는 함수
    public static boolean checkPrimeNumber(int n) {
        if(n == 1) return false;
        for(int i=2;i<n-1;i++) {
            if(n % i == 0) {
                return false;
            }
        }

        return true;
    }
}
반응형

'CodingTEST' 카테고리의 다른 글

[백준 1260] DFS와 BFS (JAVA)  (0) 2023.08.09
[백준 13023] ABCDE (JAVA)  (0) 2023.08.08
[백준 11724] 연결 요소의 개수 (JAVA)  (0) 2023.08.03
[백준 10989] 수 정렬하기 3 (JAVA)  (0) 2023.08.01
[백준 1517] 버블 소트 (JAVA)  (0) 2023.07.29