본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 2666번 벽장문의 이동 (Java)

    #2666 벽장문의 이동

    난이도 : 골드 5

    유형 : DP

     

    2666번: 벽장문의 이동

    첫 번째 줄에 벽장의 개수를 나타내는 3보다 크고 20보다 작거나 같은 하나의 정수, 두 번째 줄에 초기에 열려있는 두 개의 벽장을 나타내는 두 개의 정수, 그리고 세 번째 줄에는 사용할 벽장들

    www.acmicpc.net

    ▸ 문제

    n개의 같은 크기의 벽장들이 일렬로 붙어져 있고 벽장의 문은 n-2개만이 있다. 한 벽장 앞에 있는 문은 이웃 벽장 앞에 문이 없다면(즉, 벽장이 열려있다면) 그 벽장 앞으로 움직일 수 있다.

    그림은 7개의 벽장의 예이다. 그림에서 2번 벽장과 5번 벽장이 열려있고, 나머지 벽장은 닫혀 있다.  벽장 문은 좌우 어느 쪽이든 그 이웃 벽장이 열려 있다면 그 쪽으로 한 칸씩 이동할 수 있다. 그림에서 주어진 상태에서는 1번 벽장을 닫고 있는 벽장문을 오른쪽으로 한 칸 이동함으로써 1번 벽장을 사용할 수 있다. 이때 2번 벽장은 닫혀져 사용할 수 없다. 역시 5번 벽장이 열려 있으므로 4번 벽장 또는 6번 벽장 앞의 벽장문을 5번 벽장 앞으로 이동시킬 수 있다.

    풀어야 할 문제는 입력으로 주어지는 사용할 벽장의 순서에 따라서 벽장문을 이동하는 순서를 찾는 것이다. 이때 벽장문의 이동횟수를 최소로 하여야 한다. 입력은 다음과 같이 주어지며, 열려있는 벽장의 개수는 항상 2개이다.

    예를 들어 사용할 벽장 순서가 3 1 6 5이면, 3번 앞의 문을 2번으로 옮겨서 3번 벽장을 사용하고(문 이동횟수=1), 다음에 1번과 2번 앞에 있는 문을 오른쪽으로 하나씩 옮겨서(문 이동횟수=2) 1번 벽장을 사용하며, 6번 앞에 있는 문을 왼쪽으로 옮겨서 6번 벽장을 사용하고(문 이동횟수=1), 다시 그 문을 오른쪽으로 옮겨서 5번 벽장을 사용한다(문 이동횟수=1), 따라서 문이 이동한 횟수의 합은 5이다.

     

     입력

    첫 번째 줄에 벽장의 개수를 나타내는 3보다 크고 20보다 작거나 같은 하나의 정수, 두 번째 줄에 초기에 열려있는 두 개의 벽장을 나타내는 두 개의 정수, 그리고 세 번째 줄에는 사용할 벽장들의 순서의 길이(최대 20), 그리고 그 다음줄부터 사용할 벽장의 번호가 한줄에 하나씩 순서대로 주어진다.

     

     출력

    벽장문의 최소 이동횟수를 화면에 출력한다.

     

     

    문제 풀이 

    처음에 문제를 제대로 읽지 않아서 꽤나 고생했다. 열려있는 문의 갯수는 무조건 2개인데 그걸 읽지못하고 Queue로 할까 List로 할까 삽입 삭제가 많이 일어나는 로직은 아니니 List로 하고 했었다. 근데 그냥 열려있는 문의 갯수는 2개 고정이라서 함수 매개변수 값으로 받아 재귀를 돌리면 쉽게 적용할 수 있었다. 

     

    조건

       ∙ 벽장의 개수 n (3 < n <= 20)

       ∙ 열려있는 벽장의 수는 2개

       ∙ 사용할 벽장들의 순서의 길이 (최대 20)

     

    풀이

    1) 열려있는 2개의 벽장과 열고자하는 벽장 target[i]의 절댓값을 구한다.

    int tmp1 = Math.abs(a-target[cnt]);
    int tmp2 = Math.abs(b-target[cnt]);

     

    2) 절댓값 tmp1, tmp2중 더 가까운 곳을 선택한 후 재귀호출로 다음 벽장을 탐색시킨다.

    return Math.min(tmp1 + solve(cnt+1,b,target[cnt]),
                                      tmp2 + solve(cnt+1, a, target[cnt]));

     

     

    풀이 코드 

    import java.io.*;
    import java.util.*;
    
    public class Main {
    
    	static List<Integer> opens;
    	static int[] target;
    	public static void main(String[] args) throws IOException{
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		
    		int n = Integer.parseInt(br.readLine());
    		
    		String[] line = br.readLine().split(" ");
    		opens= new ArrayList<>();
    		for(int i=0; i<line.length; i++) {
    			opens.add(Integer.parseInt(line[i]));
    		}
    		
    		int test = Integer.parseInt(br.readLine());
    
    		target = new int[test];
    		for(int i=0; i<test; i++) {
    			target[i] = Integer.parseInt(br.readLine());
    		}
    		System.out.println(solve(0,opens.get(0),opens.get(1)));
    
    	}
        
    	static int solve(int cnt, int a, int b) {
    		
    		if(cnt == target.length) return 0;
    
    		int tmp1 = Math.abs(a-target[cnt]);
    		int tmp2 = Math.abs(b-target[cnt]);
    		
    		return Math.min(tmp1 + solve(cnt+1,b,target[cnt]),
    					tmp2 + solve(cnt+1, a, target[cnt]));
    		
    	}
    }