분류
너비 우선 탐색, 그래프 이론, 그래프 탐색
문제 설명
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 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]);
}
}'PS > Silver' 카테고리의 다른 글
| [Silver II] 섬의 개수 - 4963 (Java) (0) | 2023.08.05 |
|---|---|
| [Silver III] 1, 2, 3 더하기 - 9095 (Java) (0) | 2023.07.22 |
| [Silver III] 계단 오르기 - 2579 (0) | 2023.07.19 |
| [Silver III] 1로 만들기 - 1463 (Java) (0) | 2023.07.16 |
| [Silver IV] 설탕 배달 - 2839 (0) | 2023.07.16 |