https://www.acmicpc.net/problem/14503
[문제]
로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.
로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다. 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북중 하나이다. 지도의 각 칸은 (r, c)로 나타낼 수 있고, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로 부터 떨어진 칸의 개수이다. 로봇 청소기는 다음과 같이 작동한다.
- 현재 위치를 청소한다.
- 현재 위치에서 현재 방향을 기준으로 왼쪽 방향부터 차례대로 인접한 칸을 탐색한다.
- 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
- 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
- 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
- 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.
로봇 청소기는 이미 청소되어있는 칸을 또 청소하지 않으며, 벽을 통과할 수 없다.
[입력 조건]
- 첫째 줄에 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 50)
- 둘째 줄에 로봇 청소기가 있는 칸의 좌표 (r, c)와 바라보는 방향 d가 주어진다. d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우에는 서쪽을 바라보고 있는 것이다.
- 셋째 줄부터 N개의 줄에 장소의 상태가 북쪽부터 남쪽 순서대로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 빈 칸은 0, 벽은 1로 주어진다. 지도의 첫 행, 마지막 행, 첫 열, 마지막 열에 있는 모든 칸은 벽이다.
- 로봇 청소기가 있는 칸의 상태는 항상 빈 칸이다.
[코드]
import java.util.*;
public class BaekJoon_14503 {
static int[][] map;
static int n,m,x,y,d,count=1; // 첫 지점은 반드시 청소하기 때문에 count는 1부터 시작
static int[] dx= {-1,0,1,0}; // 북,동,남,서
static int[] dy= {0,1,0,-1};
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
x=sc.nextInt();
y=sc.nextInt();
d=sc.nextInt();
map=new int[n][m];
for(int i=0;i<n;i++) {
for(int j=0;j<m;j++) {
map[i][j]=sc.nextInt();
}
}
dfs(x,y,d);
System.out.println(count);
}
public static void dfs(int r, int c, int dir) {
map[r][c]=2; // 청소
// 4방향 탐색
for(int i=0;i<4;i++) {
dir=(dir+3)%4; // 왼쪽 방향으로 회전
int nx=r+dx[dir]; // 회전하여 이동한 좌표 계산
int ny=c+dy[dir];
// 이동한 좌표가 범위 내에 있고, 아직 청소하지 않았다면
if(map[nx][ny]==0&&nx>=0&&ny>=0&&nx<n&&ny<m) {
count++; // 청소 구역 개수 count
dfs(nx,ny,dir); // 새 좌표와 방향으로 재귀호출
/*
* 일반적인 dfs는 가다가 길이 막히면 다시 되돌아와서 해당 위치부터 계산한다.
* 하지만 해당 문제는 후진할 때만 이전 길을 되돌아가 재탐색 할 수 있으므로
* return을 해서 다시 되돌아 와도 더 이상 움직일 수 없게 만들어준다.
*/
return;
}
}
// 위의 반복문을 빠져 나왔다는 것은 주변에 더 이상 청소할 공간이 없다는 의미
int back=(dir+2)%4; // 후진할 방향 계산
int nx=r+dx[back];
int ny=c+dy[back];
// 후진한 좌표가 범위 내에 있고, 벽이 아니라면
if(map[nx][ny]!=1&&nx>=0&&ny>=0&&nx<n&&ny<m)
dfs(nx,ny,dir); // 새 좌표와, 이전 방향을 유지한채로 재귀호출
}
}
[고찰]
이번 문제는 주어진 조건을 빠짐없이 구현하면 되는 시뮬레이션 문제였다. 그 과정에서 재귀호출을 사용해하면 좀 더 효율적으로 코드를 구성할 수 있었다.
여태까지 풀어봤던 dfs 문제들과 크게 다른 점은 없었지만 한 가지 주의해야 할 점이 있었다. 일반적인 dfs 문제들은 가다가 길이 막힌다면 다시 되돌아와 다시 탐색을 시작하지만 해당 문제는 후진할 때만 이전 길을 되돌아가 재탐색 할 수 있다. 따라서 재귀호출 밑에 return 문을 적어주어야 한다. 이 점을 제외하고는 크게 어려운 점은 없었다.
'백준' 카테고리의 다른 글
[백준_9465번] 스티커 (0) | 2021.08.19 |
---|---|
[백준_9655번] 돌 게임 (0) | 2021.08.19 |
[백준_1715번] 카드 정렬하기 (0) | 2021.08.17 |
[백준_2644번] 촌수계산 (0) | 2021.08.17 |
[백준_16987번] 계란으로 계란치기 (0) | 2021.08.17 |