[백준] 12851 숨바꼭질 2 (JAVA)

2025. 9. 18. 17:11·코딩 테스트

문제링크:

12851번: 숨바꼭질 2

 

 

난이도: 골드 4

 

 

문제:

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.

 

수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 그리고, 가장 빠른 시간으로 찾는 방법이 몇 가지 인지 구하는 프로그램을 작성하시오.

 

 

입력:

첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.

 

 

출력:

첫째 줄에 수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.

둘째 줄에는 가장 빠른 시간으로 수빈이가 동생을 찾는 방법의 수를 출력한다.

 

문제 이해:

이 문제는 간단히 말해 수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생에게 도달하기 위한 최소 시간과 그 방법의 수를 구하는 것이다

 

이때 수빈이는 1초에 -1, +1, *2 만큼 이동할 수 있다

 

예제 입력 1을 보자. 시작 위치가 5이고 도착 위치가 17일 때 최단 경로는

5 → 10 → 9 → 18 → 17

5 → 4 → 8 → 16 → 17

이 두 가지가 있으며, 두 경우 모두 4초가 걸린다

 

 

구현방향:

작성자는 처음에 DFS를 사용하여 매 단계마다 세 가지 경우의 수를 탐색하고, 목적지에 도달했을 때의 시간을 리스트에 저장한 뒤 그중 최소 시간을 출력하였다. 그러나 재귀 호출의 특성상 불필요한 경로까지 모두 탐색하게 되어 시간 초과가 발생하였다.

 

이에 따라 BFS 방식으로 탐색을 변경하였다. BFS는 최단 경로 탐색에 적합하며, 탐색 과정에서 동일한 최소 시간이 여러 경로에서 나올 수 있기 때문에 단순한 visited 배열만으로는 처리가 어렵다. 따라서 각 위치에 도달하는 데 걸린 시간을 기록하고, 같은 시간에 도달한 경로를 모두 고려하여 최단 시간과 그 방법의 수를 구하도록 구현하였다.

 

이를 그대로 코드로 구현하면 다음과 같다.

 

시간초과 코드 (DFS):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class Main {
    static int N, K;
    static int count = 0; // 최적으로 가능한 방법의 수
    static int minTime = Integer.MAX_VALUE;
    // 목적지로 도달 할 수 있는 시간을 담을 리스트
    static List<Integer> resultList = new ArrayList<>();

    public static void solve(int pos, int time) {
        // 가지치기: 범위 벗어나면 종료
        if (pos < 0 || pos > 100000) return;

        // 목적지인 경우
        if (pos == K) {
            if (time < minTime) {   // 더 짧은 시간 발견
                minTime = time;
                resultList.clear(); // 이전 기록 버리고 새로 저장
                resultList.add(time);
            } else if (time == minTime) { // 같은 최단 시간 추가
                resultList.add(time);
            }
            return;
        }

        if (time > minTime) return; // 현재 시간이 최소보다 크면 더 볼 필요 없음

        // 갈 수 있는 3가지 경우의 수
        solve(pos + 1, time + 1);
        solve(pos - 1, time + 1);
        solve(pos * 2, time + 1);
    }

    public static void main(String[] args) throws IOException {
        // 초기 세팅
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());

        // 탐색 시작
        solve(N, 0);

        // 최적 경로 개수 세기
        count = resultList.size();

        // 결과 출력
        System.out.println(minTime);
        System.out.println(count);
    }
}

 

정답코드(BFS):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
    static int N, K;
    static int count = 0; // 최적으로 가능한 방법의 수
    static int[] dist = new int[100001];
    static int minTime=-1;


    public static void solve(int pos) {

        dist[N] = 0;
        Queue<int[]> q = new LinkedList<>();
        q.offer(new int[]{pos,0});

        while (!q.isEmpty()){
            //현재 위치와 시간
            int[] arr = q.poll();
            int currPos=arr[0];
            int currTime=arr[1];

            // 이미 최단 시간보다 긴 경로는 무시
            if (minTime != -1 && currTime > minTime) break;


            //목적지면
            if (currPos == K) {
                if (minTime == -1) minTime = currTime; // 첫 발견
                if (currTime == minTime) count++;
            }

            //-1 일때
            if(currPos>0&& (dist[currPos-1]==-1 || dist[currPos - 1] == currTime + 1) ){
                dist[currPos-1]=dist[currPos]+1;
                q.offer(new int[]{currPos-1,currTime+1});
            }
            //+1 일떄
            if(currPos<100000 && (dist[currPos+1]==-1|| dist[currPos + 1] == currTime + 1) ){
                dist[currPos+1]=dist[currPos]+1;
                q.offer(new int[]{currPos+1,currTime+1});
            }
            //*2 일때
            if((currPos*2)<=100000 && (dist[currPos*2]==-1 || dist[currPos *2] == currTime + 1)){
                dist[currPos*2]=dist[currPos]+1;
                q.offer(new int[]{currPos*2,currTime+1});
            }
        }


    }

    public static void main(String[] args) throws IOException {
        // 초기 세팅
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
        Arrays.fill(dist,-1);

        // 탐색 시작
        solve(N);


        // 결과 출력
        System.out.println(minTime);
        System.out.print(count);
    }
}

 

 

감사합니다.

'코딩 테스트' 카테고리의 다른 글

[백준] 17071 숨바꼭질 5 (JAVA)  (0) 2025.09.23
[백준] 13913 숨바꼭질 4 (JAVA)  (0) 2025.09.19
[백준] 16637 괄호 추가하기 (JAVA)  (0) 2025.09.17
[백준] 12869 뮤탈리스크 (JAVA)  (2) 2025.09.15
[백준] 4179 불! (JAVA)  (0) 2025.09.15
'코딩 테스트' 카테고리의 다른 글
  • [백준] 17071 숨바꼭질 5 (JAVA)
  • [백준] 13913 숨바꼭질 4 (JAVA)
  • [백준] 16637 괄호 추가하기 (JAVA)
  • [백준] 12869 뮤탈리스크 (JAVA)
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    예외처리
    BFS
    재귀
    QueryDSL
    스프링
    스프링 데이터 JPA
    코딩 테스트
    컬렉션
    예외 처리
    타임리프
    최적화
    다형성
    쿼리dsl
    thymeleaf
    쿼리
    자바
    spring
    백준
    mvc
    객체지향
    JPA
    LocalDateTime
    SpringDataJpa
    SOLID
    코딩테스트
    Java
    dfs
    fetch join
    스프링 컨테이너
    불변객체
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[백준] 12851 숨바꼭질 2 (JAVA)
상단으로

티스토리툴바