작성자 : 좌상현
문제 링크 : https://www.acmicpc.net/problem/14503

로봇 청소기와 방의 상태가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.
로봇 청소기가 있는 방은 크기의 직사각형으로 나타낼 수 있으며,
크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다.
청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북 중 하나이다. 방의 각 칸은 좌표
로 나타낼 수 있고, 가장 북쪽 줄의 가장 서쪽 칸의 좌표가 , 가장 남쪽
줄의 가장 동쪽 칸의 좌표가 이다.
즉, 좌표 는 북쪽에서 번째에 있는 줄의 서쪽에서 번째 칸을 가리킨다.
처음에 빈 칸은 전부 청소되지 않은 상태이다.로봇 청소기는 다음과 같이 작동한다.
- 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
- 현재 칸의 주변 칸 중 청소되지 않은 빈 칸이 없는 경우,
2-1. 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
2-2. 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
- 현재 칸의 주변 칸 중 청소되지 않은 빈 칸이 있는 경우,
3-1. 반시계 방향으로 회전한다.
3-2. 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다.
3-3. 1번으로 돌아간다.
입력
첫째 줄에 방의 크기 과 이 입력된다.
둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 와 처음에 로봇 청소기가 바라보는
방향 가 입력된다.
가 인 경우 북쪽, 인 경우 동쪽, 인 경우 남쪽, 인 경우 서쪽을 바라보고 있는 것이다.셋째 줄부터 개의 줄에 각 장소의 상태를 나타내는 개의 값이 한 줄에
개씩 입력된다.
번째 줄의 번째 값은 칸 의 상태를 나타내며,
이 값이 인 경우 가 청소되지 않은 빈 칸이고, 인 경우 에 벽이 있는 것이다.
방의 가장 북쪽, 가장 남쪽, 가장 서쪽, 가장 동쪽 줄 중 하나 이상에 위치한 모든 칸에는 벽이 있다. 로봇 청소기가 있는 칸은 항상 빈 칸이다.출력
로봇 청소기가 작동을 시작한 후 작동을 멈출 때까지 청소하는 칸의 개수를 출력한다.

로봇 청소기의 움직임은 다음과 같습니다.
- 현재 위치가 청소되지 않은 경우, 청소 실행
- 4방면에 청소해야 할 구역이 있다면 → 반시계 방향으로 90도 회전하면서
해당 구역 이동 후, 1번 회귀.- 4방면에 청소해야 할 구역이 없다면 → 뒤쪽 칸이 벽이 아니면 후진, 벽이면 종료
3번 경우에서 뒤쪽 칸이 벽일 때까지,
while문을 이용하여 로봇의 움직임을 제어하도록
만들었습니다.
크게는cleaning메서드를 이용하여 로봇을 제어하고, 4방면에 청소해야 할 구역이 있는지
확인하는scan메서드를 따로 구현했습니다.
또한 청소 완료한 칸의 값을2로 변경함으로서 이동은 할 수 있지만, 벽과는 구분되도록 설정했습니다.
문제에서 요구하는 대로r,c값과d값을 변경하면서 청소할때마다,cnt값을
증가시킨 후,cleaning함수가break문을 만나서 종료되면,cnt값을 출력해주면 됩니다!이 문제에서 제가 놓쳤던 부분이 있었는데,
- 로봇은 반시계 방향으로 돈다.
→ 처음에는 시계 방향으로 생각하여 방향인d값을d = (d + 1) % 4로 변경했는데,
삼항 연산자를 이용하여 반시계 방향을 구현했습니다.
import java.util.*;
import java.io.*;
public class Main {
static int n, m, r, c, d;
static int[][] room; // 0 -> 청소 x , 1 -> 벽, 2 -> 청소 완료
static int cnt = 0;
static int[] dx = {-1, 0, 1, 0};
static int[] dy = {0, 1, 0, -1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
// 방 크기 입력
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
r = Integer.parseInt(st.nextToken()); // 로봇 i
c = Integer.parseInt(st.nextToken()); // 로봇 j
d = Integer.parseInt(st.nextToken()); // 방향 (0 = 12시, 1 = 9시, 2 = 6시, 3 = 3시)
room = new int[n][m];
for(int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0; j < m; j++) {
room[i][j] = Integer.parseInt(st.nextToken());
}
}
cleaning();
System.out.println(cnt);
}
public static void cleaning() {
while(true) {
// 1. 현재 자리 청소하기
if(room[r][c] == 0) {
room[r][c] = 2;
cnt++;
}
// 2. 4방면에 치워야 할 공간 있다면
if(scan()) {
while(true) {
d = d - 1 < 0 ? d - 1 + 4 : d - 1;
if(room[r + dx[d]][c + dy[d]] == 0) {
r += dx[d];
c += dy[d];
break;
}
}
}
// 3. 4방면에 치워야 할 공간 없다면
else {
if(room[r - dx[d]][c - dy[d]] != 1) {
r -= dx[d];
c -= dy[d];
}
else {
break;
}
}
}
}
// 4방면에 청소해야 할 공간이 있는지 확인
public static boolean scan() {
for(int i = 0; i < 4; i++) {
int nx = r + dx[i];
int ny = c + dy[i];
if(nx >= 0 && nx < n && ny >= 0 && ny < m && room[nx][ny] == 0) {
return true;
}
}
return false;
}
}
중첩된 while(true)를 분리하기위해, 움직임 여부를 기준으로 반복적으로 청소하는 함수로 분리
do-while 문을 활용해서 언제나 일단! 현재 자리를 청소하는 것을 우선순위함
- 현재 자리를 청소한다(do)
- 움직일 수 있다면 움직인다.
2-1. 4방향에서 청소해야할 장소가 있다면 청소할 자리로 이동
2-2. 청소할 곳이 없다면 후진
2-3. 위 두 경우가 모두 불가능해, 움직일 수 없다면 청소 중지
import java.io.*;
import java.util.*;
public class Main {
static int n, m, r, c, d;
static int[][] room; // 0 -> 청소 x , 1 -> 벽, 2 -> 청소 완료
static int cnt = 0;
static int[] dx = {-1, 0, 1, 0};
static int[] dy = {0, 1, 0, -1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
// 방 크기 입력
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
r = Integer.parseInt(st.nextToken()); // 로봇 i
c = Integer.parseInt(st.nextToken()); // 로봇 j
d = Integer.parseInt(st.nextToken()); // 방향 (0 = 12시, 1 = 9시, 2 = 6시, 3 = 3시)
room = new int[n][m];
for(int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
for(int j = 0; j < m; j++) {
room[i][j] = Integer.parseInt(st.nextToken());
}
}
do {
cleanMySpot();
} while (isMoved());
System.out.println(cnt);
}
private static void cleanMySpot() {
if(room[r][c] == 0) {
room[r][c] = 2;
cnt++;
}
}
private static boolean isMoved() {
for(int i = 0; i < 4; i++) {
d = (d + 3) % 4; // 왼쪽 방향으로 회전
int nx = r + dx[d];
int ny = c + dy[d];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && room[nx][ny] == 0) {
r = nx;
c = ny;
return true;
}
}
if(room[r - dx[d]][c - dy[d]] != 1) {
r -= dx[d];
c -= dy[d];
return true;
}
return false;
}
}
수정자: 연이현