알고리즘/백준

14503_ 해결 못 함

베리영young 2024. 1. 9. 14:46

구현 문제로 조건이 까다롭다

1. while문을 활용했고

2. 재귀문을 활용했다

 

1. while 사용

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,1,0,-1};
    static int n,m, rx,ry, direction;
    static int[][] map, robot;
    static int answer = 0;
    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());
        rx = Integer.parseInt(st.nextToken());
        ry = Integer.parseInt(st.nextToken());
        direction = Integer.parseInt(st.nextToken());
        map = new int[n][m];
        robot = new int[n][m];
        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < m; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        robot[rx][ry] = 1; //로봇 위치 표시

        int hwak = 0;
        while (n*m>=hwak++) {
            System.out.println(hwak++);
            //현재 칸 청소
            cleanTheRoom(rx,ry);

            if(isAllClean(rx,ry)) { //청소 여부 판단 -> 빈칸없는경우
                //후진 확인
                //종료 - 후진x
                if(!canGoBack(rx,ry,direction)) break;
                //후진 후, 1번(현재 자리 청소)
                else{
                    goBack(rx,ry,direction);
                    cleanTheRoom(rx,ry);
                    //isAllClean 다시 하기
                }
            }
            else { //청소 여부 판단 -> 빈칸있는경우
                rotate90(direction);
                goFront(rx,ry); //앞이 비었따면 + 청소

            }
        }

        System.out.println(answer);
    }

    private static void goFront(int rx, int ry) {
        robot[rx][ry] = 0;
        rx += dx[direction];
        ry += dy[direction];
        robot[rx][ry] = 1;
        cleanTheRoom(rx,ry);
    }

    private static void rotate90(int direction) {
        if(direction==0) direction=3;
        else if(direction==1) direction=0;
        else if (direction==2) direction=1;
        else direction=2;
    }

    private static void goBack(int rx, int ry, int direction) {
        robot[rx][ry] = 0;
        int move = (direction+2)%4;
        robot[rx+move][ry+move] = 1; //움직이기
    }

    private static boolean isAllClean(int rx, int ry) {
        for (int d = 0; d < 4; d++) {
            int x = rx + dx[d];
            int y = ry + dy[d];
            if(x>=0&&x<n &&y>=0&&y<m && map[x][y]==0) return false; //치우러 가기
        }
        return true; //후진하기
    }

    private static void cleanTheRoom(int rx, int ry) {
        if(map[rx][ry] == 0) {
            map[rx][ry] = 2; //청소 완료!!!!!!!!!!!!!!!!!!!!!!!!
            answer++;
        }
    }

    private static boolean canGoBack(int rx, int ry, int direction) {
        int x = rx + dx[(direction+2)%4];
        int y = ry + dy[(direction+2)%4];
        if(x<0||x>=n||y<0||y>=m || map[x][y]==1 || map[x][y]==2) return false;
        return true;
    }
}

 

-> 무한 루프를 돌고 있음.

-> 4방이 모두 막힌 경우가 아닌 경우에 뭔가 처리를 해야 하는 거 같은데... 뭘까..

-> 4방 탐색 후 1과 2가 섞여있을 때가 문제인 거 같다. 뒤로 갔다 앞으로 갔다 하는 거 같음

-> 메소드를 너무 자잘하게 나누어 놓은 거 같기도 하다.

 

 

2. 재귀

import java.io.*;
import java.util.*;

public class Main {
    static int[] dx = {1,0,-1,0};
    static int[] dy = {0,1,0,-1};
    
    static int n,m, rx,ry, dir;
    static int[][] map; //로봇이 있떤 곳은 어차피 2
    static int answer = 0;
    
    public static void main(String[] args) throws IOException {
        
        inputData();
        
        operateRobot(rx, ry, dir);

        System.out.println(answer);
    }
    
    private static void operateRobot(int x, int y, int dir) {
    	//-1:로봇 0:빈칸 1:벽 2:청소된 곳
    	map[x][y] = -1; //로봇의 현재 위치:-1
        
        //4방 탐색
        for(int d=0; d<4; d++) {
        	dir = (dir + 3) % 4; //반시계로 돌기!!!!
            
            int nx = x + dx[dir];
            int ny = y + dy[dir];
            
            if(nx>=0&&nx<n&&ny>=0&&ny<m && map[nx][ny]==0) {
            	answer++;
                map[x][y] = 2;
                map[nx][ny] = -1;
                operateRobot(nx, ny, dir);
                return; //없으면 무한 돌아감
            }
            
            dir = (dir+2) %4;
            int bx = x+dx[dir];
            int by = y+dy[dir];
            
            if(bx>=0&&bx<n&&by>=0&&by<m && map[bx][by]!=1) {
            	map[x][y] = 2;
                map[bx][by] = -1;
                operateRobot(bx, by, dir);
            }
            
        }
    }
    
    
    private static void inputData() {
    	Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        rx = sc.nextInt();
        ry = sc.nextInt();
        dir =  sc.nextInt();
        
        map = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                map[i][j] = sc.nextInt();
            }
        }
    } //초기 데이터 입력 받기

}

.

=> stackOverFlow가 남. 여기도 무한 재귀를 돌고 있나?

=> 에러 확인을 할 수 없는 상황이라서 답답..

=> while보다 깔끔하게 코드가 떨어져서, 코드를 수정한다면 2번 코드를 수정하는 게 좋아 보인다.. 4방 탐색이 불가능한 경우에 처리가 더 용이해 보임