2022. 12. 19. 20:52ㆍ알고리즘/BFS 알고리즘
문제
수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.
수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 그리고, 가장 빠른 시간으로 찾는 방법이 몇 가지 인지 구하는 프로그램을 작성하시오.
입력
첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.
출력
첫째 줄에 수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.
둘째 줄에는 가장 빠른 시간으로 수빈이가 동생을 찾는 방법의 수를 출력한다.
예제 입력 1
5 17
예제 출력 1
4
2
https://www.acmicpc.net/problem/12851
다른 BFS문제와 다르게, 이 문제에서는 최소 탐색 횟수뿐만 아니라 최단 경로로 도달할 수 있는 방법의 개수까지 출력해야 한다.
방법의 개수까지 출력해야 하므로 특정 좌표를 큐에 넣자마자 방문처리를 해버린다면 이후로는 이 좌표를 통한 길이 막히므로 평소 BFS와 다른 방문처리가 필요하다.
처음 풀이에서는 BFS로 최소 탐색 횟수를 구한 뒤,
DFS를 이용해 목적지까지 도달할 수 있는 개수를 구하려고 했으나 시간초과가 났다.
그래서 다른 블로그에서 힌트를 얻었는데 그건 바로
BFS를 사용하되, 방문처리를 큐에서 꺼낼 때 하라는 것이었다.
만약 1 -> 4로 가야하는 경우에
1 -> 2 (1+1) -> 4 (2*2)
1 -> 2 (1*2) -> 4 (2*2)
이렇게 두 가지의 방법이 존재하는데 만약 1+1로 2에 도달하자마자 방문처리를 해버린다면
아래의 방법(1*2)은 카운트될 수 없는 것이다.
위의 경우에서, 방문 처리를 큐에서 뽑을 때 해준다면 두 가지 경우를 모두 count 할 수 있게된다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int n;
static int k;
static int count;
static int[] map;
static boolean[] visit;
static int MIN_TIME = Integer.MAX_VALUE;
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());
count = 1;
if (n >= k) {
System.out.println(n - k);
System.out.println(1);
return;
}
map = new int[100001];
visit = new boolean[100001];
bfs();
System.out.println(MIN_TIME);
System.out.println(count);
}
private static void bfs() {
Queue<Point> qu = new LinkedList<>();
qu.offer(new Point(n, 0));
visit[n] = true;
while (!qu.isEmpty()) {
Point point = qu.poll();
visit[point.x] = true;
if (point.x == k) {
if (MIN_TIME > point.time) {
MIN_TIME = point.time;
} else if (MIN_TIME == point.time) {
count++;
}
continue;
}
int[] dx = {point.x + 1, point.x - 1, point.x * 2};
for (int i = 0; i < 3; i++) {
int next = dx[i];
if (0 < next && next < 100001 && !visit[next]) {
qu.offer(new Point(next, point.time + 1));
}
}
}
}
static class Point{
int x;
int time;
public Point(int x, int time) {
this.x = x;
this.time = time;
}
}
}
'알고리즘 > BFS 알고리즘' 카테고리의 다른 글
백준 5427: 불 [Java] -포포 (0) | 2023.01.03 |
---|---|
백준 1707: 이분 그래프 [Java] - 포포 (0) | 2022.12.17 |
백준 2668: 숫자고르기 [Java] -포포 (0) | 2022.12.15 |
백준 2251: 물통 [Java] - 포포 (1) | 2022.12.13 |
백준 14426: 이모티콘 [Java] - 포포 (0) | 2022.11.23 |