CS/Algorism

[백준] 1525. 퍼즐

olsohee 2024. 2. 6. 16:53

https://www.acmicpc.net/problem/1525

 

1525번: 퍼즐

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

www.acmicpc.net

  • 퍼즐에서 0의 위치를 찾아서 4방향(위, 아래, 왼쪽, 오른쪽)으로 bfs를 진행하면 된다.
  • 그런데 해당 퍼즐을 이미 만들었다면 패스하는 로직을 작성해야 한다. 이때 이차원 배열로 비교하면 복잡하기 때문에 다음과 같이 문자열로 변경해서 생각하면 된다.
    • 1 2 3 
      4 5 6
      7 8 0
    • ➡️ 123456780
  • 그리고 방문 여부뿐만 아니라 몇 번만에 해당 퍼즐을 만들었는지 저장해주어야 하는데 map을 사용하면 방문 여부와 횟수를 간편하게 저장할 수 있다. map의 key는 중복이 불가하므로 key에 퍼즐의 문자열을 담아주고, value에 몇 번만에 해당 문자열(퍼즐)을 만들었는지 기록하면 된다.
  • 내가 가장 크게 실수한 부분은 다음과 같다.
    • 처음에 0의 위치를 위, 아래, 왼쪽, 오른쪽으로 이동하는 로직을 인덱스 -3, +3, -1, +1로 두어서 계산했었다.
    • 그런데 이렇게 하면 다음의 경우 문제가 발생한다. 0은 가장 오른쪽에 있기 때문에 오른쪽으로 이동할 수 없다. 그런데 내가 생각한 로직으로는 0과 3이 바뀌게 되는 문제가 발생한다. 
      • 1 2 0
        3 4 5
        6 7 8
    • 따라서 이 점에 주의해서 코드를 작성해주어야 한다. 올바르게 작성한 코드는 다음과 같다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Map<String, Integer> map = new HashMap<>();
    static Queue<String> que = new LinkedList<>();

    public static void main(String[] args) throws IOException {

        String start = "";
        for (int i = 0; i < 3; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < 3; j++) {
                start += Integer.parseInt(st.nextToken());
            }
        }

        // bfs
        map.put(start, 0); // 시작점은 누적 count가 0
        que.add(start);
        while (!que.isEmpty()) {
            String now = que.poll();

            if (now.equals("123456780")) {
                System.out.println(map.get(now));
                return;
            }

            int zeroIdx = now.indexOf("0");

            // 위와 바꾸기
            if (zeroIdx > 2) {
                int moveIdx = zeroIdx - 3;
                move(now, moveIdx);
            }

            // 아래와 바꾸기
            if (zeroIdx < 6) {
                int moveIdx = zeroIdx + 3;
                move(now, moveIdx);
            }

            // 오른쪽과 바꾸기
            if (zeroIdx != 2 && zeroIdx != 5 && zeroIdx != 8) {
                int moveIdx = zeroIdx + 1;
                move(now, moveIdx);
            }

            // 왼쪽과 바꾸기
            if (zeroIdx != 0 && zeroIdx != 3 && zeroIdx != 6) {
                int moveIdx = zeroIdx - 1;
                move(now, moveIdx);
            }
        }
        System.out.println(-1);
    }

    private static void move(String now, int moveIdx) {
        // 움직이기
        String newStr = new String(now);

        char moveNum = now.charAt(moveIdx);
        newStr = newStr.replace(moveNum, 'c');
        newStr = newStr.replace('0', moveNum);
        newStr = newStr.replace('c', '0');

        // 방문 여부 확인 후 방문 안했으면, 방문 처리(map) 후 큐에 넣기
        if (!map.containsKey(newStr)) {
            map.put(newStr, map.get(now) + 1);
            que.add(newStr);
        }
    }
}

'CS > Algorism' 카테고리의 다른 글

[2022 KAKAO TECH INTERNSHIP] 등산코스 정하기  (1) 2024.02.13
[백준] 2212. 센서  (1) 2024.02.08
[백준] 5014. 스타트링크  (1) 2024.02.05
[백준] 1987. 알파벳  (0) 2024.02.02
[백준] 11403. 경로 찾기  (0) 2024.02.02