CS/Algorism

[백준] 1261. 알고스팟

olsohee 2024. 4. 11. 13:09

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

 

1261번: 알고스팟

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다. 다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미

www.acmicpc.net

  • bfs를 통해 (0, 0)부터 (n-1, m-1)까지 이동하면 된다.
  • 다음 노드가 방이면 이어서 이동하고, 다음 노드가 벽이면 부수고 이동한다. 즉, 큐에 벽을 부순 횟수도 담아주어야 한다. 그리고 벽을 부쉈을 때 굳이 1을 0으로 변경해줄 필요가 없으며, 방문처리만 해주면 된다.
  • 중요한 점은 우선순위 큐를 사용해서, 벽을 부순 횟수가 적은 노드부터 꺼내야 한다는 것이다.
    • 만약 방문처리를 안해주면 이미 방문한 곳을 계속 방문하므로 무한하게 탐색한다. 따라서 방문처리는 필수이다.
    • 그런데 방문처리를 하면, 하나의 노드로 도착하는 경로의 경우의 수는 단 1개이다. 이미 a라는 경로로 (n-1, m-1) 노드에 도착했으면, (n-1, m-1)에 방문처리가 되어있으므로 b라는 경로로 (n-1, m-1)로 도착하지 못하기 때문이다.
    • 즉, 방문처리를 하면 (n-1, m-1) 노드로 도착하는 여러 경로 중, 벽을 부순 횟수가 적은 경로보다 벽을 부순 횟수가 많은 경로가 먼저 (n-1, m-1) 노드로 도착할 수 있으며, 해당 경로가 유일한 경로가 된다.
    • 따라서 우선순위 큐를 이용하여 벽을 부순 횟수가 적은 경로를 우선으로 탐색하도록 한다. 그러면 (n-1, m-1) 노드로 처음이자 유일하게 도착하는 경로는 벽을 가장 적게 부수는 경로가 된다.
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 int m; // 가로
    static int n; // 세로
    static int[][] map;
    static boolean[][] visited;
    static int[] dx = {1, -1, 0, 0};
    static int[] dy = {0, 0, 1, -1};
    static int answer;

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

        // 입력
        st = new StringTokenizer(br.readLine());
        m = Integer.parseInt(st.nextToken());
        n = Integer.parseInt(st.nextToken());
        map = new int[n][m];
        visited = new boolean[n][m];

        for (int i = 0; i < n; i++) {
            String[] str = br.readLine().split("");
            for (int j = 0; j < m; j++) {
                map[i][j] = Integer.parseInt(str[j]);
            }
        }

        // 0,0을 시작으로 bfs
        Queue<Node> que = new PriorityQueue<>(); // 우선순위 큐(breakCnt가 적은 노드가 우선)
        visited[0][0] = true;
        que.add(new Node(0, 0, 0));

        while (!que.isEmpty()) {
            Node now = que.poll();

            // 도착점에 도착한 경우 bfs 끝내기 (해당 경로가 가장 적게 벽을 부순 경로임)
            if (now.x == m - 1 && now.y == n - 1) {
                answer = now.breakCnt;
                break;
            }

            for (int i = 0; i < 4; i++) {
                int nx = dx[i] + now.x;
                int ny = dy[i] + now.y;

                if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;
                if (visited[ny][nx]) continue;

                // 다음 노드가 0이라면 그대로 이동
                if (map[ny][nx] == 0) {
                    visited[ny][nx] = true;
                    que.add(new Node(ny, nx, now.breakCnt));
                }
                // 다음 노드가 1(벽)이라면 부수고 이동 
                if (map[ny][nx] == 1) {
                    visited[ny][nx] = true;
                    que.add(new Node(ny, nx, now.breakCnt + 1));
                }
            }
        }

        System.out.println(answer);
    }

    public static class Node implements Comparable<Node> {

        int y, x;
        int breakCnt;

        public Node(int y, int x, int breakCnt) {
            this.y = y;
            this.x = x;
            this.breakCnt = breakCnt;
        }

        @Override
        public int compareTo(Node o) {
            return this.breakCnt - o.breakCnt;
        }
    }
}

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

[백준] 8980. 택배  (0) 2024.04.16
[백준] 16929. Two Dots  (0) 2024.04.12
[백준] 17182. 우주 탐사선  (0) 2024.04.11
[백준] 2531. 회전 초밥  (0) 2024.04.10
[백준] 2146. 다리 만들기  (0) 2024.04.10