
문제 요약
알고스팟 운영진이 모두 미로에 갇혔다. 미로는 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)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.
문제 분석
- 시작점에서부터 BFS(너비 우선 탐색)을 사용하여 각 위치까지의 최소 벽 부수기 횟수를 계산한다.
- 우선순위 큐(PriorityQueue)를 사용하여 벽 부수기 횟수가 작은 순서대로 노드를 처리한다.
- 이를 통해 최소 벽 부수기 횟수로 도착점에 도달하는 경로를 찾는다.
- 상하좌우로 이동하면서 새로운 위치를 탐색하고, 해당 위치의 정보를 큐에 추가한다.
- 도착점에 도달하면 최소 벽 부수기 횟수를 업데이트하고 처리를 종료한다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static int N,M, result;
static int[][] map;
static int[] dr = {1, 0, -1, 0};
static int[] dc = {0, 1, 0, -1};
static class Node implements Comparable<Node> {
int r;
int c;
int breakCnt;
public Node(int r, int c, int breakCnt) {
this.r = r;
this.c = c;
this.breakCnt = breakCnt;
}
@Override
public int compareTo(Node o) {
if(this.breakCnt < o.breakCnt) {
return -1;
} else if(this.breakCnt > o.breakCnt) {
return 1;
}
return 0;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());;
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
if(N == 1 && M == 1){
System.out.println(0);
return;
}
map = new int[N][M];
for(int r = 0; r < N; r++){
String temp = br.readLine();
for(int c = 0; c < M; c++){
map[r][c] = Character.getNumericValue(temp.charAt(c));
}
}
// for(int[] a : map){
// System.out.println(Arrays.toString(a));
// }
result = Integer.MAX_VALUE;
boolean[][] v = new boolean[N][M];
v[0][0] = true;
bfs(0,0,0, v);
System.out.println(result);
}
private static void bfs(int r, int c, int wallCnt, boolean[][] v){
PriorityQueue<Node> q = new PriorityQueue<>();
q.add(new Node(r,c,0));
while(!q.isEmpty()){
Node node = q.poll();
for(int d = 0; d < 4; d++) {
int nr = node.r + dr[d];
int nc = node.c + dc[d];
int breakCnt = node.breakCnt;
if (nr < 0 || nc < 0 || nr >= N || nc >= M) {
continue;
}
if(nr == N-1 && nc == M-1){
// 도착
result = Math.min(result, breakCnt);
continue;
}
if(v[nr][nc] == false){
v[nr][nc] = true;
q.add(new Node(nr,nc,breakCnt + (map[nr][nc] == 1 ? 1 : 0)));
}
}
}
}
}
정리
더 찾아볼만한 사항
이전에 비슷한 문제를 덱을 사용한 0-1BFS로 풀었던 적이 있는데 이번 로직과 저번 로직 중 어떤 로직이 더 효율적인지 모르겠다.
'알고리즘 풀이 > 백준' 카테고리의 다른 글
[Silver II] 원숭이 매달기 - 2716 (Java) (0) | 2023.08.22 |
---|---|
[Gold V] IPv6 - 3107 (Java) (0) | 2023.08.19 |
[Gold V] 빗물 - 14719 (Java) (1) | 2023.08.08 |
[Gold IV] 가르침 - 1062 (Java) (1) | 2023.08.08 |
[Silver I] 전쟁 - 전투 - 1303 (JAVA) (0) | 2023.08.08 |