2206번: 벽 부수고 이동하기
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로
www.acmicpc.net
💡풀이💡
(1,1)에서 (N,M)까지 이동하는 최단 경로를 구하는 것이기 때문에 BFS!
이동하는 중에 1개의 벽을 부술 수 있기 때문에 특정점 (a,b)까지 갈 때 벽을 부숴서 (a,b)까지 이동한 경우와
벽을 부수지 않고 이동한 경우 두 가지를 고려해야한다!
1. 입력 받기
import java.io.*;
import java.util.*;
public class Main {
static int[] dr = {-1,0,1,0}; // 상우하좌
static int[] dc = {0,1,0,-1}; // 상우하좌
static int R, C, min;
static int[][] map;
static boolean[][][] v;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
map = new int[R][C];
for(int i=0; i<R; i++) {
String str = br.readLine();
for(int j=0; j<C; j++) {
map[i][j] = str.charAt(j)-'0';
}
}
br.close();
}
}
2. 이동하기 - BFS
최단 경로를 구해야 하기 때문에 BFS로 이동
큐에 r,c, 벽 부순 횟수, (r,c)에 도착한 깊이를 저장
벽을 부수지 않고 이동 가능한 곳과 벽을 부수고 이동 가능한 곳을 모두 큐에 추가
(N,M)에 도착할 수 있다면 둘 중 빠르게 이동한 방법이 먼저 poll()되기 때문에 답을 구할 수 있음!
1) 벽을 부수지 않고 이동했으면 v[r][c][0]에 저장
2) 벽을 부수고 이동했으면 v[r][c][1]에 저장
System.out.println(bfs(0, 0));
static int bfs(int r, int c) {
ArrayDeque<int[]> q = new ArrayDeque<>();
// v[r][c][0] : 벽 부수지 않고 (r,c)에 도착 , v[r][c][1] : 벽 부수고 (r,c)에 도착
v = new boolean[R][C][2];
v[r][c][0] = true;
q.offer(new int[] {r,c,0,1}); //r, c, 벽 부순 횟수, depth
while(!q.isEmpty()) {
int[] cur = q.poll();
int cnt = cur[2];
int depth = cur[3];
// 도착지에 도착했으면
if(cur[0]==R-1 && cur[1]==C-1) return depth;
// 벽 부수지 않고 이동
for(int d=0; d<4; d++) {
int nr = cur[0] + dr[d];
int nc = cur[1] + dc[d];
//범위 안에 있고, 방문하지 않았고, 이동가능한 곳이면
if(0<=nr&&nr<R && 0<=nc&&nc<C && !v[nr][nc][cnt] && map[nr][nc]==0) {
v[nr][nc][cnt] = true;
q.offer(new int[] {nr, nc, cnt, depth+1});
}
}
if(cnt >=1) continue; // 벽을 부수지 못하면
// 벽 부수고 이동
for(int d=0; d<4; d++) {
int nr = cur[0] + dr[d];
int nc = cur[1] + dc[d];
//범위 안에 있고, 방문하지 않았고, 벽이면
if(0<=nr&&nr<R && 0<=nc&&nc<C && !v[nr][nc][1] && map[nr][nc]==1) {
v[nr][nc][1] = true;
q.offer(new int[] {nr, nc, cnt+1, depth+1});
}
}
}
return -1;
}
전체 코드
import java.io.*;
import java.util.*;
public class Main {
static int[] dr = {-1,0,1,0}; // 상우하좌
static int[] dc = {0,1,0,-1}; // 상우하좌
static int R, C, min;
static int[][] map;
static boolean[][][] v;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine(), " ");
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
map = new int[R][C];
for(int i=0; i<R; i++) {
String str = br.readLine();
for(int j=0; j<C; j++) {
map[i][j] = str.charAt(j)-'0';
}
}
System.out.println(bfs(0, 0));
br.close();
}
static int bfs(int r, int c) {
ArrayDeque<int[]> q = new ArrayDeque<>();
// v[r][c][0] : 벽 부수지 않고 (r,c)에 도착 , v[r][c][1] : 벽 부수고 (r,c)에 도착
v = new boolean[R][C][2];
v[r][c][0] = true;
q.offer(new int[] {r,c,0,1}); //r, c, 벽 부순 횟수, depth
while(!q.isEmpty()) {
int[] cur = q.poll();
int cnt = cur[2];
int depth = cur[3];
// 도착지에 도착했으면
if(cur[0]==R-1 && cur[1]==C-1) return depth;
// 벽 부수지 않고 이동
for(int d=0; d<4; d++) {
int nr = cur[0] + dr[d];
int nc = cur[1] + dc[d];
//범위 안에 있고, 방문하지 않았고, 이동가능한 곳이면
if(0<=nr&&nr<R && 0<=nc&&nc<C && !v[nr][nc][cnt] && map[nr][nc]==0) {
v[nr][nc][cnt] = true;
q.offer(new int[] {nr, nc, cnt, depth+1});
}
}
if(cnt >=1) continue; // 벽을 부수지 못하면
// 벽 부수고 이동
for(int d=0; d<4; d++) {
int nr = cur[0] + dr[d];
int nc = cur[1] + dc[d];
//범위 안에 있고, 방문하지 않았고, 벽이면
if(0<=nr&&nr<R && 0<=nc&&nc<C && !v[nr][nc][1] && map[nr][nc]==1) {
v[nr][nc][1] = true;
q.offer(new int[] {nr, nc, cnt+1, depth+1});
}
}
}
return -1;
}
}
'알고리즘 문제풀이 > 백준' 카테고리의 다른 글
[백준 1015] 수열 정렬 (0) | 2023.05.05 |
---|---|
[백준 9020] 골드바흐의 추측 (0) | 2023.04.25 |
[백준 16987] 계란으로 계란치기 (0) | 2023.04.04 |
[백준 9205] 맥주 마시면서 걸어가기 (0) | 2023.04.03 |
[백준 14502] 연구소 (0) | 2023.03.30 |
댓글