문제

알고스팟 운영진이 모두 미로에 갇혔다. 미로는 N*M 크기이며, 총 1*1크기의 방으로 이루어져 있다. 미로는 빈 방 또는 벽으로 이루어져 있고, 빈 방은 자유롭게 다닐 수 있지만, 벽은 부수지 않으면 이동할 수 없다.

알고스팟 운영진은 여러명이지만, 항상 모두 같은 방에 있어야 한다. 즉, 여러 명이 다른 방에 있을 수는 없다. 어떤 방에서 이동할 수 있는 방은 상하좌우로 인접한 빈 방이다. 즉, 현재 운영진이 (x, y)에 있을 때, 이동할 수 있는 방은 (x+1, y), (x, y+1), (x-1, y), (x, y-1) 이다. 단, 미로의 밖으로 이동 할 수는 없다.

벽은 평소에는 이동할 수 없지만, 알고스팟의 무기 AOJ를 이용해 벽을 부수어 버릴 수 있다. 벽을 부수면, 빈 방과 동일한 방으로 변한다.

만약 이 문제가 알고스팟에 있다면, 운영진들은 궁극의 무기 sudo를 이용해 벽을 한 번에 다 없애버릴 수 있지만, 안타깝게도 이 문제는 Baekjoon Online Judge에 수록되어 있기 때문에, sudo를 사용할 수 없다.

현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.

 

 

입력

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

(1, 1)과 (N, M)은 항상 뚫려있다.

 

 

출력

첫째 줄에 알고스팟 운영진이 (N, M)으로 이동하기 위해 벽을 최소 몇 개 부수어야 하는지 출력한다.

 

 

예제

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
 
public class Main_BJ_1261_알고스팟 {
    static int [][] map;
    static boolean [][] visited;
    static int [] dx= {-1,0,1,0};
    static int [] dy= {0,1,0,-1};
    static int N,M;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine()," ");
        
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        
        map = new int[M][N];
        visited = new boolean[M][N];
        
        for(int i=0;i<M;i++) {
            String str = br.readLine();
            for(int j=0;j<N;j++) map[i][j] = str.charAt(j)-48;
        }
        
        int result = bfs();
        System.out.println(result);
 
    }
    
    public static int bfs() {
        PriorityQueue<int []> queue = new PriorityQueue<>(new Comparator<int []>() {
 
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[2]-o2[2];
            }
        });
        
        queue.add(new int[]{0,0,0});
        visited[0][0]= true;
        
        while(!queue.isEmpty()) {
            int [] temp = queue.poll();
            int x = temp[0];
            int y = temp[1];
            int cnt = temp[2];
            if(x==M-1 && y==N-1) {
                return cnt;
            }
            for(int i=0;i<4;i++) {
                int nx = x+dx[i];
                int ny = y+dy[i];
                
                if(range(nx,ny) && !visited[nx][ny]) {
                    visited[nx][ny] = true;
                    if(map[nx][ny]==1) queue.offer(new int[] {nx,ny,cnt+1});
                    else queue.offer(new int[] {nx,ny,cnt});
                }
            }
        }
        return 0;
    }
    
    public static boolean range(int x, int y) {
        return x>=0 && y>=0 && x<&& y<N;
    }
 
}
cs

 

 

풀이 방법

미로의 가장 왼쪽 위인(0,0)에서 가장 오른쪽 아래(M-1, N-1)의 위치로 이동하기 위해 최소한으로 몇 개의 벽을 부수는지 알아내는 문제였습니다. 저는 bfs()를 사용해서 구현했습니다. 먼저 시작점인 (0,0)과 함께 벽을 부슨 개수를 기억하기 위해 벽을 부순 횟수인 cnt와 함께 우선순위 큐에 저장해주었습니다. 우선순위 큐를 사용한 이유는 가장 적은 수의 벽을 부순 개수를 찾아야 하기 때문에 우선순위 큐를 이용하여 cnt값이 가장 작은 것을 기준으로 진행하였습니다. 만약 도착점인 (M-1, N-1)에 도착했다면 도착지까지의 벽을 부순 횟수인 cnt 값을 리턴해 주었습니다.

 

 

 

'문제 > 백준' 카테고리의 다른 글

백준 2665번 미로만들기 [JAVA]  (0) 2021.03.25
백준 5427번 불 [JAVA]  (0) 2021.03.25
백준 2636번 치즈 [JAVA]  (0) 2021.03.24
백준 18405번 경제적 전염 [JAVA]  (0) 2021.03.23
백준 1966번 프린터 큐 [JAVA]  (0) 2021.03.23

+ Recent posts