[JAVA] 백준 14503번 로봇 청소기 자바 풀이

시뮬레이션 구현 문제입니다.

📚 문제

🔗 문제 링크

백준 14503번: 로봇 청소기

📖 문제 설명

  • 로봇 청소기가 있는 장소는 N×M 크기의 직사각형
  • 각 칸은 빈 칸(0) 또는 벽(1)
  • 로봇 청소기는 동서남북 중 하나를 바라보는 방향이 있음
  • 로봇 청소기는 다음 규칙으로 작동:
    1. 현재 칸이 청소되지 않은 경우, 현재 칸을 청소
    2. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 없는 경우:
      • 바라보는 방향을 유지한 채로 한 칸 후진할 수 있으면 후진하고 1번으로 돌아감
      • 후진할 수 없으면 작동을 멈춤
    3. 현재 칸의 주변 4칸 중 청소되지 않은 빈 칸이 있는 경우:
      • 반시계 방향으로 90도 회전
      • 바라보는 방향을 기준으로 앞쪽 칸이 청소되지 않은 빈 칸인 경우 한 칸 전진
      • 1번으로 돌아감

🔍 입력 조건

  • 첫째 줄에 N, M (3 ≤ N, M ≤ 50)
  • 둘째 줄에 로봇 청소기의 초기 위치(r, c)와 방향 d
  • 셋째 줄부터 N개의 줄에 장소의 상태 (빈 칸은 0, 벽은 1)

🔍 출력 조건

  • 로봇 청소기가 청소하는 칸의 개수를 출력

🧩 문제 분류

  • 알고리즘: 구현, 시뮬레이션
  • 난이도: GOLD V

🚀 접근 방법

  1. 로봇 클래스를 구현하여 진행
  2. dx, dy 활용하여 동서남북 검사
    • 탐색 순서가 정해져 있지 않기 때문에 dx, dy의 방향 순서는 중요하지 않다.
  3. 청소 상태를 처리하기 위한 추가 배열을 활용

💻 구현

/**
 * BAEKJOON ONLINE JUDGE
 * 문제 이름 : 로봇 청소기
 * 문제 번호 : 14503
 * 난이도 : GOLD V
 */

import java.util.Scanner;

public class Main {
    private static final int MAX_N = 50;
    private static final int[] DX = {-1, 0, 1, 0};
    private static final int[] DY = {0, 1, 0, -1};
    private static final int DSIZE = 4;

    static int N, M;
    static int[][] map = new int[MAX_N][MAX_N];
    static boolean[][] clean = new boolean[MAX_N][MAX_N];
    static class Robot{
        int x, y;   // 좌표
        int d;      // 바라보는 방향

        public Robot(int x, int y, int d){
            this.x = x;
            this.y = y;
            this.d = d;
        }

        // 로봇 청소기의 작동
        public void run(){
            while (true){
                // 현재 칸 청소
                this.clean();

                // 청소되지 않은 빈 칸이 없는 경우
                if (checkClean()){
                    int nx = x - DX[d];
                    int ny = y - DY[d];

                    if (map[nx][ny] == 1) break;

                    this.x = nx;
                    this.y = ny;

                    continue;
                }

                // 청소되지 않은 빈 칸이 없는 경우
                d = (d + 3) % 4;    // 반시계 회전

                int nx = x + DX[d];
                int ny = y + DY[d];

                // 앞 쪽이 청소되지 않은 빈 칸인 경우 한 칸 전진
                if(map[nx][ny] == 0 && !clean[nx][ny]){
                    this.x = nx;
                    this.y = ny;
                }
            }
        }
        // 범위 검사
        private boolean inRange(int x, int y){
            return 0 <= x && x < N && 0 <= y && y < M;
        }

        // 주변에 청소되지 않은 빈 칸이 없는 경우 true 반환
        private boolean checkClean(){
            for (int i = 0; i < DSIZE; i++){
                int nx = x + DX[i];
                int ny = y + DY[i];

                if (!inRange(nx, ny) || map[nx][ny] == 1) continue;

                if (!clean[nx][ny]) return false;
            }

            return true;
        }

        // 해당 칸을 청소한다.
        public void clean(){
            if (!clean[x][y]) clean[x][y] = true;
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();

        int r = sc.nextInt();
        int c = sc.nextInt();
        int d = sc.nextInt();

        Robot robot = new Robot(r, c, d);   // 로봇 생성

        // 맵 설정
        for (int i = 0; i < N; i++){
            for (int j = 0; j < M; j++){
                map[i][j] = sc.nextInt();
            }
        }

        robot.run();    // 로봇 작동

        // 청소된 칸 개수 출력
        int answer = 0;
        for (int i = 0; i < N; i++){
            for (int j = 0; j < M; j++){
                if (clean[i][j]) answer++;
            }
        }

        System.out.println(answer);
    }
}

⏱ 시간 복잡도

  • O(N×M): 최악의 경우 모든 칸을 방문
  • 각 칸에서 최대 4번의 방향 전환 가능

💾 공간 복잡도

  • O(N×M): 지도를 저장하는 2차원 배열 사용

📝 회고

  • 이 문제처럼 객체의 이동을 보여주는 문제를 풀 때는, 객체를 생성해서 객체 입장으로 구현하는게 효과적인 것 같다.
  • 객체가 바라보는 방향이나, 회전, 이동을 객체 내부 메서드로 구현하는 게 좋다.
  • 이 문제는 로봇 청소기의 단일 이동이라서 까다로운 문제는 아니었지만, 여러 객체가 필요하거나 동시다발적인 이동을 구현할 때 더 유용한 방법이라고 생각된다.