ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 14503
    Java/코딩테스트 2023. 4. 6. 01:28

    https://www.acmicpc.net/problem/14503

     

    14503번: 로봇 청소기

    첫째 줄에 방의 크기 $N$과 $M$이 입력된다. $(3 \le N, M \le 50)$  둘째 줄에 처음에 로봇 청소기가 있는 칸의 좌표 $(r, c)$와 처음에 로봇 청소기가 바라보는 방향 $d$가 입력된다. $d$가 $0$인 경우 북쪽

    www.acmicpc.net

    바보같이 이동 방향 배열 순서를 잘못 정의해서 한참 고민한 문제... 

    난이도는 삼성 기출중에 그래도 쉬운 편에 속하는것 같은데 오래 걸렸다....북-동-남-서 방향으로 가야하는데 아무 생각없이 동서남북으로 정의해뒀어서😂

     

    🍇 케이스 정의

    #1) 현재칸이 0인 경우 -> clean()

    #2) 주변 4칸에 청소가 되지 않은 빈칸이 있는지 탐색한다 -> findAround()

    #2-1) 주변 4칸 중 청소 가능한 칸이 있다면 (findAround() == true) 현재 방향 기준 반시계방향으로 방향을 틀면서 가능한 위치로 이동한다. (goToClean)

    #2-2) 주변 4칸이 다 청소되거나 벽이라면 후진을 시도한다(goBack()) 

    후진 안되는 경우에는 탐색을 종료하고 정답을 출력한다.

     

     

     

    🍇 메소드 목록 

    - 메인함수

    - 탐색용 함수 (BFS / DFS 둘다 써봤고 채점 해봤는데 DFS가 공간 효율적인 측면에서 조금 더 좋았다. 두 메소드 다 코드에 넣어둠)

    - 청소 : 해당 칸을 -1로 바꾼다. 참고로 1로 바꾸면 후진할때 갈 수 있는데 못간다고 판정할 수 있으므로 0,1말고 다른 값으로 바꾸면 된다. 난 그냥 -1로 해둠 

    - 주변 4칸 중 청소 가능한 칸 있는지 탐색하는 findAround() : true/false따라 2-1로갈지 2-2로 갈지 결정

    - 2-1의 경우 goToClean() : 반시계방향으로 틀면서 가능한 위치로 move() 

    - 2-2의 경우 goBack() : 뒷 칸이 벽이 아닌지 확인후 move()  [ 또는 isFinished() = true -> bfs쓸때 필요해서 선언해둠, DFS는 재귀형태라 굳이 필요 없을 것 같다 ]


    🍇 코드 내용 

    1. 메인 함수 및 static 변수들 선언

        static int[] dirX = { -1, 0, 1, 0 };
        static int[] dirY = { 0, 1, 0, -1 };
        static int[][] room;
        static int n, m, answer;
        static int curX, curY, curDir;
        static boolean isFinished = false;
        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());
            answer = 0;
            room = new int[n][m];
    
            // 현재 좌표, 보고 있는 방향 설정
            st = new StringTokenizer(br.readLine());
            curX = Integer.parseInt(st.nextToken());
            curY = Integer.parseInt(st.nextToken());
            curDir = Integer.parseInt(st.nextToken());
    
            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());
                }
            }
    
            DFS(curX, curY);
            // 또는 BFS(curX, curY);
            System.out.println(answer);
        }

    2. DFS 함수

    첨에 BFS 써야할 것 같다고 생각했다. 실제로 저 코드로 구현해놓고 BFS재귀적으로 계속 호출을 하게끔 돌렸는데 답이 나오긴한다. 그치만 공간 메모리 규모는 DFS가 더 좋기도 하고 ... 굳이 최단 경로 찾는건 아니어서 DFS로 푸는 듯 하다. 코드도 DFS가 더 간결... 

     

    flag 가 주변 4칸 중 가도 되는 곳이 있냐?! 를 나타내는 변수이므로 이거에 따라서 청소하러 갈지(goToClean()), 후진할지 (goBack()) 결정! 

    참고로 방문 여부는 청소한 상태 == -1이면 이미 간거니까 0일때만 이동하게끔 하면 된다. 

    /* public static void BFS(int x, int y) {
            Queue<int[]> queue = new LinkedList<>();
            int [] pos = { x, y };
            queue.add(pos);
    
            while (!queue.isEmpty()) {
                int[] poll = queue.poll();
                int tempX = poll[0];
                int tempY = poll[1];
    
                if (room[tempX][tempY] == 0) {
                    clean(tempX, tempY);
                }
                boolean flag = findAround(tempX, tempY);
                if (flag) {
                    goToClean();
                    int[] temp = { curX, curY };
                    queue.add(temp);
                } else {
                    goBack();
                    if (isFinished) {
                        break;
                    }
                }
            }
        } */
        
    public static void DFS(int x, int y) {
            if (room[x][y] == 0) {
                clean(x, y);
            }
            boolean flag = findAround(x, y);
            if (flag) {
                goToClean();
            } else {
                goBack();
            }
    }

    3. 해당 칸 청소하는 함수 / 주변 칸 탐색하는 함수 / 유효한 좌표인지 확인하는 함수( 지도상의 크기가 혹시 넘어가지 않도록? ) 

    public static void clean(int x, int y) {
            room[x][y] = -1;
            answer += 1;
        }
    
    // 주변 4칸 중 청소되지 않은 빈 칸이 있는지 없는지 여부 확인
    public static boolean findAround(int x, int y) {
            for (int i = 0; i < 4; i++) {
                int nextX = x + dirX[i];
                int nextY = y + dirY[i];
                if (validPos(nextX, nextY)) {
                    if (room[nextX][nextY] == 0) {
                        // 청소되지 않은 빈칸
                        return true;
                    }
                }
            }
            return false;
    }
    
    public static boolean validPos (int x, int y) {
    	if (x < 0 || x >= n || y < 0 || y >= m) {
                return false;
        }
        return true;
    }

    4. 이동시키는 함수, 2-1,2 처리하는 goToClean() & goBack()

    move에 굳이 dir 안 들어가도 될 것 같다...차피 curDir은 static 이라 상관 없을 듯 

    public static void move(int x, int y, int dir) {
            curX = x;
            curY = y;
            curDir = dir;
            DFS(curX, curY);
    }

    방향 돌릴 때는 3더하고 나머지 4 연산해주면 된다

    public static void goToClean() {
            int tempDir = curDir;
            // 반시계 방향 회전
            for (int i = 0; i < 4; i++) {
                tempDir = (tempDir + 3) % 4;
                int nextX = curX + dirX[tempDir];
                int nextY = curY + dirY[tempDir];
                
                if (validPos(nextX, nextY)) {
                    if (room[nextX][nextY] == 0) {
                        curDir = tempDir;
                        move(nextX, nextY, curDir);
                        break;
                    }
                }
            }
    }
    
        // 주변에 청소되지 않은 빈칸 없어서 후진해야하는 경우
        // curDir은 바꾸지 않는다.
    public static void goBack() {
            int nextX = curX - dirX[curDir];
            int nextY = curY - dirY[curDir];
    
            if (!validPos(nextX, nextY) || room[nextX][nextY] == 1) {
                isFinished = true;
            }
            else {
                move(nextX, nextY, curDir);
            }
    }

    'Java > 코딩테스트' 카테고리의 다른 글

    백준 17142  (0) 2023.04.08
    백준 15686  (0) 2023.04.06
    [ DFS / BFS ] 개념 및 예제 정리  (0) 2023.04.05
    [DP] 백준 풀이 기록 JAVA (Feat. do it 알고리즘 코딩테스트)  (0) 2023.04.05
    백준 11003(Java)  (0) 2022.08.07
Designed by Tistory.