https://www.acmicpc.net/problem/14503
크기의 격자판에서 로봇 청소기가 정해진 복잡한 규칙에 따라 이동하며 청소한 칸의 총 개수를 계산하는 문제이다.
이 문제의 경우 상태(위치, 방향)가 매 순간 변하며, 이 변화가 다음 행동을 결정하는 전형적인 시뮬레이션(Simulation) 문제로.이 문제의 핵심은
'문제 설명에 나온 4가지 행동 규칙을 어떻게 정확하게 코드로 구현하는가'이다.
1. 현재 칸 청소 (규칙 1)
2. 주변 4칸 탐색 (규칙 2, 3의 분기점)
3. 후진 또는 정지 (규칙 2)
3. 회전 및 전진 (규칙 3)
위와 같이 대부분의 시뮬레이션 문제들은 명확한 우선순위와 순서를 가지기 때문에 순서를 파악하고 순차적인 로직을 올바르게 구현하는 것이 포인트이다.
N, M과 2차원 matrix배열에 방의 상태(0:빈칸, 1:벽)를 입력 받는다.result변수를 0으로 초기화dr, dc를 정의break)까지 다음 로직을 무한 반복matrix[r][c] == 0일 경우 matrix[r][c]를 2로 변경하고 result를 1증가시킨다(result++, 2는 청소 완료를 의미)isValid 플래그를 만들고 4방향을 탐색하여 matrix[nr][nc] == 0 (청소 가능)이 있는지 확인if(!isValid): 청소할 칸이 없는 경우(nr, nc)를 계산matrix[nr][nc] == 1 (벽)이면 break로 루프를 탈출한다.(작동 중지)r = nr, c = nc로 후진하고 continue를 통해 초기로 돌아간다.else: 청소할 칸이 있는 경우d = (d + 3) % 4로 반시계 방향으로 90도 회전(nr, nc)를 계산matrix[nr][nc] == 0이면 r = nr, c = nc로 전진 (전진 못해도 초기로 돌아감)while문이 종료되면 result 값을 출력한다.
(총 반복횟수) x (1회 반복당 연산량)으로 계산
if (matrix[r][c] == 0)...: for (int i = 0; i < 4; i++)...: , 즉 최대 총 반복 횟수는 이차원 배열의 모든 (행, 열)을 방문했을 경우이다.
따라서 인 이다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class gold5_14503_로봇청소기 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
// 0: 북 1:동 2:남 3:서
int[] dr = { -1, 0, 1, 0 };
int[] dc = { 0, 1, 0, -1 };
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
int d = Integer.parseInt(st.nextToken());
int[][] matrix = new int[N][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
matrix[i][j] = Integer.parseInt(st.nextToken());
}
}
int result = 0;
// 로봇 청소기 로직
while (true) {
int nr;
int nc;
// 현재칸 청소
if (matrix[r][c] == 0) {
matrix[r][c] = 2;
result++;
}
// 청소구역 확인
boolean isValid = false;
// 4방향 탐색으로 청소해야될 구역이 있는지 확인
for (int i = 0; i < 4; i++) {
nr = r + dr[i];
nc = c + dc[i];
// 청소할 수 있는 구역이 있는 경우
if (matrix[nr][nc] == 0) {
isValid = true;
}
}
// 청소 구역이 없는 경우
if (!isValid) {
// 후진이 가능한지 확인
nr = r + dr[(d + 2) % 4];
nc = c + dc[(d + 2) % 4];
// 벽이 아니어야 함
if (!(matrix[nr][nc] == 1)) {
// 후진 후 처음으로 이동
r = nr;
c = nc;
continue;
}
// 벽인 경우 작동 중지
else {
break;
}
}
// 청소 구역이 있는 경우
else {
// 반시계 방향 회전
d = (d + 3) % 4;
nr = r + dr[d];
nc = c + dc[d];
// 바라보는 방향 기준 앞쪽 칸이 청소되지 않았으면 한칸 전진
if (matrix[nr][nc] == 0) {
r = nr;
c = nc;
}
}
}
System.out.println(result);
}
}