숨바꼭질 4 - JAVA

J-USER·2021년 9월 7일
0

알고리즘

목록 보기
13/13
post-thumbnail

문제

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

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

입력

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

출력

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

둘째 줄에 어떻게 이동해야 하는지 공백으로 구분해 출력한다.

문제 풀이

이전의 숨바꼭질 2에서 bfs로 최소 시간을 구할 수 있었지만 이번에는 그 경로를 함께 출력해야한다.
최소 시간을 찾기 위해서는 1개의 1차원 배열이 필요했지만...
경로를 알기 위해서는 2개의 1차원 배열이 필요하다. 이 생각은 어디서 나왔냐면... 프로그래머스의 호텔방 지정하기?? 라는 문제에서 해시 맵을 이용한 남은 방 탐색이 기억이 났다.

그렇기 때문에 따지고보면 배열도 인덱스라는 키를 바탕으로 값에 접근하는 구조이다.

그래서 알고리즘으로는 먼저,

  • q에 저장된 좌표 확인.
  • 좌표가 K와 같다면,
    - path[N] 을 시작으로 union_find 알고리즘에서 find_parent만 진행
    -역출력
  • 좌표가 K와 같지 않다면, bfs로 q에 다음 이동이 가능한지 체크.
  • 다음 이동 후보군에 현재시간+1을 저장(시간) && 다음 경로의 값에 현재 좌표 저장(경로).
  • q에 이동 가능 add.
  • 반복.
package algorithm.BOJ.bfs_dfs;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;

public class 숨바꼭질4 {
	public static void main(String[] args) {
			Scanner sc = new Scanner(System.in);
			int N = sc.nextInt();
			int K = sc.nextInt();
			int[] visite = new int[100000+1]; // key = 위치 , value = 시간.
			int[] path   = new int[100000+1]; // key = 현재위치 , value = 이전위치.
			
			visite[N] = 1;
			path[N] = N;
			
			Queue<Integer> q = new LinkedList<Integer>();
			q.add(N);
			while(!q.isEmpty()) {
				
				int now = q.poll();
				
				if (now == K) 
				{
					System.out.println(visite[now] -1);
					Stack<Integer> st =new Stack<>();
					while(path[now] != now) 
					{
						st.add(now);
						now = path[now];
					}
					
					st.add(N);
					
					StringBuilder sb = new StringBuilder();
	                while (!st.isEmpty())
	                    sb.append(st.pop() + " ");
	                System.out.println(sb.toString());
	                
					return;
				}
				
				int[] move = {now*2,now+1,now-1};
				
				for(int i = 0 ; i < 3; i++){
					int next = move[i];
					if(next < 0|| next > 100000 || visite[next] != 0) continue;
					
					visite[next] = visite[now] +1; //현재시간에 +1 저장.
					path[next] = now; // 다음 좌표에, 어디서 왔는지 저장.
					q.add(next); // 후보군 등록.
				}
			}
			
	}
}
profile
호기심많은 개발자

0개의 댓글