[백준 14503 / Gold5] 로봇 청소기 - Java(자바)

토끼굴·2025년 5월 15일

❓문제 설명


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

로봇 청소기와 방의 상태가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.

로봇 청소기가 있는 방은 N×MN \times M 크기의 직사각형으로 나타낼 수 있으며,
1×11 \times 1 크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다.
청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북 중 하나이다. 방의 각 칸은 좌표
(r,c)(r, c)로 나타낼 수 있고, 가장 북쪽 줄의 가장 서쪽 칸의 좌표가 (0,0)(0, 0), 가장 남쪽
줄의 가장 동쪽 칸의 좌표가 (N1,M1)(N-1, M-1)이다.
즉, 좌표 (r,c)(r, c)는 북쪽에서 (r+1)(r+1)번째에 있는 줄의 서쪽에서 (c+1)(c+1)번째 칸을 가리킨다.
처음에 빈 칸은 전부 청소되지 않은 상태이다.

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 칸이 아직 청소되지 않은 경우, 현재 칸을 청소한다.
  1. 현재 칸의 주변 44칸 중 청소되지 않은 빈 칸이 없는 경우,
    2-1. 바라보는 방향을 유지한 채로 한 칸 후진할 수 있다면 한 칸 후진하고 1번으로 돌아간다.
    2-2. 바라보는 방향의 뒤쪽 칸이 벽이라 후진할 수 없다면 작동을 멈춘다.
  1. 현재 칸의 주변 44칸 중 청소되지 않은 빈 칸이 있는 경우,
    3-1. 반시계 방향으로 9090^\circ 회전한다.
    3-2. 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진한다.
    3-3. 1번으로 돌아간다.

❗제약 조건


입력
첫째 줄에 방의 크기 NNMM이 입력된다. (3N,M50)(3 \le N, M \le 50)
둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 (r,c)(r, c)와 처음에 로봇 청소기가 바라보는
방향 dd가 입력된다.
dd00인 경우 북쪽, 11인 경우 동쪽, 22인 경우 남쪽, 33인 경우 서쪽을 바라보고 있는 것이다.

셋째 줄부터 NN개의 줄에 각 장소의 상태를 나타내는 N×MN \times M개의 값이 한 줄에
MM개씩 입력된다.
ii번째 줄의 jj번째 값은 칸 (i,j)(i, j)의 상태를 나타내며,
이 값이 00인 경우 (i,j)(i, j)가 청소되지 않은 빈 칸이고, 11인 경우 (i,j)(i, j)에 벽이 있는 것이다.
방의 가장 북쪽, 가장 남쪽, 가장 서쪽, 가장 동쪽 줄 중 하나 이상에 위치한 모든 칸에는 벽이 있다. 로봇 청소기가 있는 칸은 항상 빈 칸이다.

출력
로봇 청소기가 작동을 시작한 후 작동을 멈출 때까지 청소하는 칸의 개수를 출력한다.


🎁 문제 풀이


로봇 청소기의 움직임은 다음과 같습니다.

  1. 현재 위치가 청소되지 않은 경우, 청소 실행
  2. 4방면에 청소해야 할 구역이 있다면 → 반시계 방향으로 90도 회전하면서
    해당 구역 이동 후, 1번 회귀.
  3. 4방면에 청소해야 할 구역이 없다면 → 뒤쪽 칸이 벽이 아니면 후진, 벽이면 종료

3번 경우에서 뒤쪽 칸이 벽일 때까지, while 문을 이용하여 로봇의 움직임을 제어하도록
만들었습니다.
크게는 cleaning 메서드를 이용하여 로봇을 제어하고, 4방면에 청소해야 할 구역이 있는지
확인하는 scan 메서드를 따로 구현했습니다.
또한 청소 완료한 칸의 값을 2 로 변경함으로서 이동은 할 수 있지만, 벽과는 구분되도록 설정했습니다.
문제에서 요구하는 대로 r,c 값과 d값을 변경하면서 청소할때마다, cnt 값을
증가시킨 후, cleaning 함수가 break 문을 만나서 종료되면, cnt 값을 출력해주면 됩니다!

이 문제에서 제가 놓쳤던 부분이 있었는데,

  1. 로봇은 반시계 방향으로 돈다.
    → 처음에는 시계 방향으로 생각하여 방향인 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 문을 활용해서 언제나 일단! 현재 자리를 청소하는 것을 우선순위함

  1. 현재 자리를 청소한다(do)
  2. 움직일 수 있다면 움직인다.
    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;
  }

}

수정자: 연이현

profile
10마리의 토끼가 열심히 공부 중.. 집단 지성으로 성장해요.

0개의 댓글