
| 시간 제한 | 메모리 제한 | 제출 | 정답 | 맞힌 사람 | 정답 비율 | 
|---|---|---|---|---|---|
| 2 초 | 512 MB | 34719 | 11590 | 8159 | 31.294% | 
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.
수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.
첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.
첫째 줄에 수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.
둘째 줄에 어떻게 이동해야 하는지 공백으로 구분해 출력한다.
5 17
4
5 10 9 18 17
5 17
4
5 4 8 16 17
문제를 만든 사람: baekjoon
비슷한 문제
1697번. 숨바꼭질
12851번. 숨바꼭질 2
13549번. 숨바꼭질 3
그래프 이론
그래프 탐색
너비 우선 탐색
import java.io.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
    public static int n, k;
    public static boolean[] visited;
    public static int[] dx = {2, 1, -1};
    public static class Node {
        int x, time;
        String move;
        Node(int x, int time, String move) {
            this.x = x;
            this.time = time;
            this.move = move;
        }
    }
    public static Queue<Node> q;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        q = new LinkedList<Node>();
        visited = new boolean[100001];
        q.offer(new Node(n, 0, String.valueOf(n)));
        visited[n] = true;
        Node returnNode = findBro();
        if(returnNode == null) {
            bw.write("-1");
        } else {
            bw.write(String.valueOf(returnNode.time) + "\n");
            String[] strArr = returnNode.move.split(" ");
            for(int k = 0; k < strArr.length; k++) {
                bw.write(strArr[k] + " ");
            }
        }
        bw.flush();
        bw.close();
        br.close();
    }
    public static Node findBro() {
        while(!q.isEmpty()) {
            Node cur = q.poll();
            String curMove = cur.move;
            if(cur.x == k) return cur;
            for(int k = 0; k < 3; k++) {
                int nx = 0;
                if(k == 0) {
                    nx = cur.x * dx[k];
                } else {
                    nx = cur.x + dx[k];
                }
                if(isNotRange(nx) || visited[nx]) continue;
                q.offer(new Node(nx, cur.time+1, curMove+" "+String.valueOf(nx)));
                visited[nx] = true;
            }
        }
        return null;
    }
    public static boolean isNotRange(int x) {
        return (x < 0 || x >= 100001) ? true : false;
    }
}
import java.io.*;
import java.sql.Array;
import java.util.*;
public class Main {
    public static int n, k;
    public static boolean[] visited;
    public static int[] bfMove;
    public static int[] dx = {2, 1, -1};
    public static class Node {
        int x, time;
        Node(int x, int time) {
            this.x = x;
            this.time = time;
        }
    }
    public static Queue<Node> q;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        q = new LinkedList<Node>();
        visited = new boolean[100001];
        bfMove = new int[100001];
        Arrays.fill(bfMove, -1);
        q.offer(new Node(n, 0));
        visited[n] = true;
        // 동생을 찾는데 걸리는 최소 시간
        bw.write(String.valueOf(findBro()) + "\n");
        // 경로 역으로 추적하기
        int i = k;
        List<String> strList = new ArrayList<String>();
        strList.add(String.valueOf(k));
        while(bfMove[i] != -1) {
            strList.add(String.valueOf(bfMove[i]));
            i = bfMove[i];
        }
        
        // 역순으로 되어있으므로 반대로 출력
        for(int k = strList.size()-1; k >= 0; k--) {
            bw.write(strList.get(k) + " ");
        }
        bw.flush();
        bw.close();
        br.close();
    }
    public static int findBro() {
        while(!q.isEmpty()) {
            Node cur = q.poll();
            if(cur.x == k) return cur.time;
            for(int k = 0; k < 3; k++) {
                int nx = 0;
                if(k == 0) {
                    nx = cur.x * dx[k];
                } else {
                    nx = cur.x + dx[k];
                }
                // 맵의 범위를 벗어나거나, 이미 방문한 칸인 경우 skip
                if(isNotRange(nx) || visited[nx]) continue;
                q.offer(new Node(nx, cur.time+1));      // 큐에 등록
                visited[nx] = true;                          // 방문처리
                bfMove[nx] = cur.x;                          // 이전에 거쳐온 칸 기억
            }
        }
        return -1;
    }
    public static boolean isNotRange(int x) {
        return (x < 0 || x >= 100001) ? true : false;
    }
}
처음에 지금까지 온 경로를 계속 누적해서 들고다니려고 했더니 시간 초과가 발생했다. 수빈이가 100000에 있고, 동생이 0에 있는 경우라면 100000 ~ 0 까지 계속 누적해서 경로를 들고다닐테니 시간초과가 발생한다...
그래서 배열을 하나 더 생성하여 바로 이전 위치만 기억하도록 한 후, 수빈이가 동생을 찾았을 때 그때부터 바로 이전의 위치들을 반복적으로 꺼내어 경로를 찾아낼 수 있었다.
list에 담아서 처리하였지만, stack에 담는게 더 나았을 것 같다.