백준 13549 숨바꼭질 3 Java 풀이는 모든 이동의 비용이 같지 않다는 점에서 일반 BFS와 다르다. 처음 풀었을 때의 기록에는 두 번째 제출에서 통과했고 50분 timer가 6분 36초 남아 있었다고 적혀 있다. 첫 제출이 왜 틀렸는지는 남아 있지 않으므로 원인을 지어내기보다, 최종 풀이가 보장해야 할 순서를 0-1 BFS 기준으로 다시 정리했다.
이동을 weight가 있는 edge로 바꾼다
현재 위치가 x일 때 이동은 세 가지다.
| 다음 위치 | 걸리는 시간 | edge weight |
|---|---|---|
2 * x |
0초 | 0 |
x - 1 |
1초 | 1 |
x + 1 |
1초 | 1 |
일반 BFS는 모든 edge weight가 같을 때 queue에 들어온 순서가 곧 최단 거리 순서가 된다. 여기서는 순간이동이 0초이므로 단순 FIFO queue만으로 그 성질을 설명하기 어렵다.
weight가 0 또는 1뿐인 graph에서는 deque를 사용한다.
- weight 0으로 이동:
addFirst - weight 1로 이동:
addLast
비용이 늘지 않는 순간이동 후보를 앞쪽에서 먼저 처리하고, 1초가 필요한 이동은 뒤쪽에 둔다. relaxation으로 더 짧은 시간이 발견됐을 때만 deque에 넣는다.
Java 풀이
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.StringTokenizer;
public class Main {
private static final int MAX_POSITION = 100_000;
private static final int INF = Integer.MAX_VALUE;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int start = Integer.parseInt(st.nextToken());
int target = Integer.parseInt(st.nextToken());
System.out.println(zeroOneBfs(start, target));
}
private static int zeroOneBfs(int start, int target) {
int[] distance = new int[MAX_POSITION + 1];
Arrays.fill(distance, INF);
Deque<Integer> deque = new ArrayDeque<>();
distance[start] = 0;
deque.addFirst(start);
while (!deque.isEmpty()) {
int current = deque.pollFirst();
int teleported = current * 2;
if (teleported <= MAX_POSITION
&& distance[teleported] > distance[current]) {
distance[teleported] = distance[current];
deque.addFirst(teleported);
}
int left = current - 1;
if (left >= 0
&& distance[left] > distance[current] + 1) {
distance[left] = distance[current] + 1;
deque.addLast(left);
}
int right = current + 1;
if (right <= MAX_POSITION
&& distance[right] > distance[current] + 1) {
distance[right] = distance[current] + 1;
deque.addLast(right);
}
}
return distance[target];
}
}
예제로 확인하기
입력:
5 17
출력:
2
최소 시간 2초를 만드는 경로 중 하나는 다음과 같다.
5 -> 10 (0초)
10 -> 9 (1초)
9 -> 18 (0초)
18 -> 17 (1초)
start == target이면 답은 0이다. start > target인 경우에도 -1 이동을 반복하는 경로가 relaxation되어 올바른 시간이 나온다. 위치 범위를 0..100000으로 고정했으므로 -1, +1, *2를 넣기 전에 범위를 확인한다.
복잡도와 자료형
상태는 0..100000의 위치이고 각 위치에서 최대 3개의 edge만 확인한다.
- 시간 복잡도:
O(MAX_POSITION) - 공간 복잡도: distance와 deque에
O(MAX_POSITION) - 자료형: 최단 시간은 위치 범위보다 작으므로
int로 충분하다.
일반 graph와 BFS의 기본은 그래프 자료구조와 DFS·BFS 차이, 임의의 양수 weight에서 priority queue를 사용하는 방식은 백준 1504 특정한 최단 경로에서 비교할 수 있다.
참고 자료
'배움과 성장 > 알고리즘·문제풀이' 카테고리의 다른 글
| 백준 2559 수열 Java: 누적합으로 연속 K일 최대 합 구하기 (0) | 2022.05.10 |
|---|---|
| 백준 11066 파일 합치기 Java: 누적합과 구간 DP 점화식 (0) | 2022.05.08 |
| 백준 2470 두 용액 Java: 정렬과 투 포인터로 0에 가까운 합 찾기 (0) | 2022.05.05 |
| 백준 3273 두 수의 합 Java: 정렬과 투 포인터로 pair 세기 (0) | 2022.05.05 |
| 백준 1504 특정한 최단 경로 Java: 다익스트라 3번으로 두 경로 비교 (2) | 2022.05.04 |
댓글