알고리즘/[ Baekjoon ]

[ BOJ ][JAVA][1525] 퍼즐

kim.svadoz 2021. 4. 18. 21:50
반응형

www.acmicpc.net/problem/1525

 

1525번: 퍼즐

세 줄에 걸쳐서 표에 채워져 있는 아홉 개의 수가 주어진다. 한 줄에 세 개의 수가 주어지며, 빈 칸은 0으로 나타낸다.

www.acmicpc.net

시간 제한 메모리 제한 제출 정답 맞은 사람 정답 비율
1 초 32 MB (하단 참고) 10769 4546 2738 40.521%

문제

3×3 표에 다음과 같이 수가 채워져 있다. 오른쪽 아래 가장 끝 칸은 비어 있는 칸이다.

1 2 3
4 5 6
7 8  

어떤 수와 인접해 있는 네 개의 칸 중에 하나가 비어 있으면, 수를 그 칸으로 이동시킬 수가 있다. 물론 표 바깥으로 나가는 경우는 불가능하다. 우리의 목표는 초기 상태가 주어졌을 때, 최소의 이동으로 위와 같은 정리된 상태를 만드는 것이다. 다음의 예를 보자.

1   3
4 2 5
7 8 6
1 2 3
4   5
7 8 6
1 2 3
4 5  
7 8 6
1 2 3
4 5 6
7 8  

가장 윗 상태에서 세 번의 이동을 통해 정리된 상태를 만들 수 있다. 이와 같이 최소 이동 횟수를 구하는 프로그램을 작성하시오.

입력

세 줄에 걸쳐서 표에 채워져 있는 아홉 개의 수가 주어진다. 한 줄에 세 개의 수가 주어지며, 빈 칸은 0으로 나타낸다.

출력

첫째 줄에 최소의 이동 횟수를 출력한다. 이동이 불가능한 경우 -1을 출력한다.

예제 입력 1

1 0 3
4 2 5
7 8 6

예제 출력 1

3

예제 입력 2

3 6 0
8 1 2
7 4 5

예제 출력 2

-1

코드

import java.io.*;
import java.util.*;

public class p1525 {
    static BufferedReader br;
    static StringTokenizer st;
    static int[] dx = {1, 0, -1, 0};
    static int[] dy = {0, 1, 0, -1};
    static boolean[] visit;
    static HashMap<Integer, Integer> map;
    static Queue<Integer> q;
    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));

        // 2차원 퍼즐을 1차원으로 바꾸기
        int start = 0;
        for (int i = 0; i < 3; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < 3; j++) {
                int tmp = Integer.parseInt(st.nextToken());
                if (tmp == 0) tmp = 9;
                start = (start * 10) + tmp;
            }
        }

        q = new LinkedList<>();
        map = new HashMap<>();

        q.offer(start);
        map.put(start, 0);

        System.out.println(bfs());       
    }

    static int bfs() {
        while (!q.isEmpty()) {
            // 처음 퍼즐의 상태를 문자열로 바꿔 빈공간의 위치를 찾는다.
            int cur = q.poll();
            String cur_str = String.valueOf(cur);

            if (cur_str.equals("123456789")) {
                return map.get(cur);
            }

            // 현재 빈 좌표
            int nine = cur_str.indexOf('9');
            // 몫 연산은 행, 나머지 연산은 열
            int r = nine / 3;
            int c = nine % 3;

            for (int i = 0; i < 4; i++) {
                int nr = r + dx[i];
                int nc = c + dy[i];

                if (nr < 0 || nr >= 3 || nc < 0 || nc >= 3) continue;
                StringBuilder next_str = new StringBuilder(cur_str);
                // nr * 3 + nc 는 좌표의 1차원 배열에서의 위치
                char tmp = next_str.charAt(nr * 3 + nc);
                // 이전 빈칸과 다음 위치의 숫자를 바꾼다.
                next_str.setCharAt(nr * 3 + nc, '9');
                next_str.setCharAt(nine, tmp);

                int next = Integer.parseInt(next_str.toString());

                // 맵에 없는 경우(나온 적 없는 퍼즐의 상태)에는 맵에 추가한다.
                if (!map.containsKey(next)) {
                    map.put(next, map.get(cur) + 1);
                    q.offer(next);
                }
            }
        }
        return -1;
    }
}
반응형

'알고리즘 > [ Baekjoon ]' 카테고리의 다른 글

[ BOJ ][JAVA][1644] 소수의 연속합  (0) 2021.04.18
[ BOJ ][JAVA][1613] 역사  (0) 2021.04.18
[ BOJ ][JAVA][1520] 내리막 길  (0) 2021.04.18
[ BOJ ][JAVA][1517] 버블 소트  (0) 2021.04.18
[ BOJ ][JAVA][1476] 날짜 계산  (0) 2021.04.18