문제 링크

분류

너비 우선 탐색, 그래프 이론, 그래프 탐색

 

문제 설명

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

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

 

입력

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

 

출력

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

 

실패한 풀이(BFS + DP 원인: 메모리 초과)

시간 복잡도 O(n) 공간 복잡도 O(n)

아이디어: DP풀이 방식을 적용하여 DP테이블을 모든 공간 만큼 생성시키고 수빈이가 각 칸에 도달 할 수 있는 모든 경우의 수를 체크 및 지속적으로 갱신하여 Math.min() 수빈이가 동생에 도달 하기 전까지 최대한 모든 칸에 도착 할 수 있는 최소 시간의 값을 재갱신 

큐에 수빈이가 도착 할 수 있는 모든 경우를 입력

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        Queue<ArrayList<Integer>> queue = new LinkedList<>();
        int[] map = new int[100001];
        Arrays.fill(map,200000);
        ArrayList<Integer> ans = new ArrayList<>();
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());

        map[n] = 0;
        ArrayList<Integer> node = new ArrayList<>(List.of(n));
        queue.add(node);

        while(!queue.isEmpty()){
            ArrayList<Integer> cur = queue.poll();
            ArrayList<Integer> tmp = new ArrayList<>();
            for (Integer pos : cur) {
                if(pos+1<=100000) {
                    map[pos + 1] = Math.min(map[pos + 1], map[pos] + 1);
                    tmp.add(pos+1);
                }
                if(pos-1>=0) {
                    map[pos - 1] = Math.min(map[pos - 1], map[pos] + 1);
                    tmp.add(pos-1);
                }
                if(2*pos<=100000) {
                    map[pos * 2] = Math.min(map[pos * 2], map[pos] + 1);
                    tmp.add(pos*2);
                }
            }
            if(map[k]!=200000||tmp.isEmpty())
                break;

            queue.add(tmp);
        }

        System.out.println(map[k]);
    }
}

 

성공한 풀이(BFS)

시간 복잡도 O(n) 공간 복잡도 O(n)

아이디어: 수빈이가 각 칸에 도달 할 수 있는 모든 경우의 수를 체크 및 지속적으로 갱신하여 Math.min() 수빈이가 동생에 도달 하기 전까지 최대한 모든 칸에 도착 할 수 있는 최소 시간의 값을 재갱신 하는 기존 로직에서 

생각을 좀 더 해보면 현 사이클(시간:n) 이 아닌 그 이후 사이클(시간:n+1)에 도착을 할 것이기 때문에

굳이 모든 경우를 체크 할 필요 없이 만약 이미 해당 칸에 도착한 적이 있다면 큐에 추가하지 않기 때문에

불필요한 이동을 막아 실패한 풀이에 비해 메모리 낭비를 줄일 수 있다.

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

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        Queue<int[]> queue = new LinkedList<>();
        int[] map = new int[100001];
        Arrays.fill(map,-1);
        ArrayList<Integer> ans = new ArrayList<>();
        int n = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());

        map[n] = 0;
        queue.add(new int[]{n, 0});

        while(!queue.isEmpty()){
            int[] current = queue.poll();
            int pos = current[0];
            int time = current[1];

            if (pos == k) {
                System.out.println(time);
                break;
            }

            if (pos - 1 >= 0 && map[pos - 1] == -1) {
                map[pos - 1] = time + 1;
                queue.add(new int[]{pos - 1, time + 1});
            }
            if (pos + 1 <= 100000 && map[pos + 1] == -1) {
                map[pos + 1] = time + 1;
                queue.add(new int[]{pos + 1, time + 1});
            }
            if (pos * 2 <= 100000 && map[pos * 2] == -1) {
                map[pos * 2] = time + 1;
                queue.add(new int[]{pos * 2, time + 1});
            }
        }
        System.out.println(map[k]);
    }
}

+ Recent posts