본문 바로가기

카테고리 없음

[프로그래머스/JAVA] 코딩테스트 연습 > 연습문제 > 리코쳇 로봇(by 다알쥐AI)

728x90

[리코쳇 로봇] 코딩테스트 연습 > 연습문제 > 리코쳇 로봇

 

 

※ 주의 : 문제풀이 방법은 다양합니다. 참고만 해주세요

[문제설명]

더보기

리코쳇 로봇이라는 보드게임이 있습니다.

 

이 보드게임은 격자모양 게임판 위에서 말을 움직이는 게임으로, 시작 위치에서 출발한 뒤 목표 위치에 정확하게 멈추기 위해 최소 몇 번의 이동이 필요한지 말하는 게임입니다.

 

이 게임에서 말의 이동은 현재 위치에서 상, 하, 좌, 우 중 한 방향으로 게임판 위의 장애물이나 게임판 가장자리까지 부딪힐 때까지 미끄러져 움직이는 것을 한 번의 이동으로 정의합니다.

 

다음은 보드게임판을 나타낸 예시입니다. ("."은 빈 공간을, "R"은 로봇의 처음 위치를, "D"는 장애물의 위치를, "G"는 목표지점을 나타냅니다.)

...D..R
.D.G...
....D.D
D....D.
..D....

이때 최소 움직임은 7번이며 "R" 위치에서 아래, 왼쪽, 위, 왼쪽, 아래, 오른쪽, 위 순서로 움직이면 "G" 위치에 멈춰 설 수 있습니다.

게임판의 상태를 나타내는 문자열 배열 board가 주어졌을 때, 말이 목표위치에 도달하는데 최소 몇 번 이동해야 하는지 return 하는 solution함수를 완성해주세요. 만약 목표위치에 도달할 수 없다면 -1을 return 해주세요.


제한 사항

  • 3 ≤ board의 길이 ≤ 100
    • 3 ≤ board의 원소의 길이 ≤ 100
    • board의 원소의 길이는 모두 동일합니다.
    • 문자열은 ".", "D", "R", "G"로만 구성되어 있으며 각각 빈 공간, 장애물, 로봇의 처음 위치, 목표 지점을 나타냅니다.
    • "R"과 "G"는 한 번씩 등장합니다.

입출력 예



입출력 예 설명

입출력 예 #1

  • 문제 설명의 예시와 같습니다.

입출력 예 #2

.D.R
....
.G..
...D
  • "R" 위치에 있는 말을 어떻게 움직여도 "G" 에 도달시킬 수 없습니다.
  • 따라서 -1을 return 합니다.

[간단설명]

리코쳇 Rule을 이용해서 시작점에서 종료점까지 최소 이동횟수 구하기

** 리코쳇 로봇이해하기 

ㄴ 한번 이동시에 1칸씩 움직이는게 아니라, 장애물 or 벽을 만났때까지 이동한다.

 

[접근방법]

1. 시작점, 종료점을 찾는다.

2. 최소값을 지정한다.

3. 큐를 사용해서 BFS 탐색을 구현한다.(최단거리)

4. 위, 아래, 왼쪽, 오른쪽 전부 탐색한다.

5. 방문한 좌표는 탐색하지 않는다.

6. 최소값이 바뀌지 않았으면 -1을 리턴한다.(종료점에 도달하지 못했으면)

7. 이동횟수 최소값을 리턴한다.

 

[주의사항]

- 방문체크를 하지 않으면, 효율성에서 탈락한다.

- 종료점에 도달하지 못하는 경우는 -1을 리턴해야한다.(여기에서는 최소값으로 구분)

- 귀찮아서 통과할 정도로만 소스를 구현했는데, 다른 간결한 방법도 찾아보자

 

[소스공개]

import java.util.*;
class Solution {
    public int solution(String[] board) {
        // 시작점, 종료점 배열
        int[] start = new int[2];
        int[] end  = new int[2];
        // 시작점, 종료점 찾기
        for(int i=0;i<board.length;i++){
            for(int j=0;j<board[0].length();j++){
                if('R'==board[i].charAt(j)){
                    start=new int[]{i,j,0,0};
                }else if('G'==board[i].charAt(j)){
                    end=new int[]{i,j,0,0};
                }
            }
        }
        // 방문기록
        boolean[][] visited = new boolean[board.length][board[0].length()];
        // BFS용 queue
        Queue<int[]> que = new LinkedList<>();
        // 시작점을 큐에 넣는다.
        que.offer(start);
        int min = 10000; // board 길이 100 x 원소길이 100 = 10,000
        // BFS 탐색
        while(!que.isEmpty()){
            // 현재 que 가져오기
            int[] now = que.poll();
            // 종료점에 도착했으면, 최소값 업데이트
            if(now[0] == end[0] && now[1] == end[1]){
                min=Math.min(now[3],min);
                break;
            }
            // 방문했으면 PASS
            if(visited[now[0]][now[1]]) continue;
            // 방문체크
            visited[now[0]][now[1]]= true;
            
            // 위로 이동
            // 이동할 수 있을때만, 큐에 넣는다.
            int[] up = move(board,now,"up",now[3]);
            if(up[2]==0){
                que.offer(up);
            }
            // 아래로 이동
            int[] down = move(board,now,"down",now[3]);
            if(down[2]==0){
                que.offer(down);
            }
            // 왼쪽 이동
            int[] left = move(board,now,"left",now[3]);
            if(left[2]==0){
                que.offer(left);
            }
            // 오른쪽 이동
            int[] right = move(board,now,"right",now[3]);
             if(right[2]==0){
                que.offer(right);
            }
          
        }
        // 종료점에 도달하지 못하면 -1 리턴
        if(min==10000) return -1;
        // 최소값 리턴
        return min;
    }
    
    private int[] move(String[] board,int[] now, String direction, int sum){
        int y=now[0]; // y좌표
        int x=now[1]; // x좌표
        // 명령어가 up이면
        if("up".equals(direction)){
            // 경계를 벗어나면, -1리턴
            if(y-1 < 0) {
                return new int[]{y,x,-1,sum};
            }
            // 범위에 있으면, sum+1 리턴
            else{
                int cnt=0;
                for(int i=y-1;i>=0;i--){
                    if('D'==board[i].charAt(x)){
                        break;
                    }else{
                        cnt++;
                    }
                }
                return new int[]{y-cnt,x,0,sum+1};
            }
        // 명령어가 down이면
        }else if("down".equals(direction)){
            if(y+1 > board.length-1) {
                return new int[]{y,x,-1,sum};
            }
            else{
                int cnt=0;
                for(int i=y+1;i<board.length;i++){
                    if('D'==board[i].charAt(x)){
                        break;
                    }else{
                        cnt++;
                    }
                }
                return new int[]{y+cnt,x,0,sum+1};
            }
        // 명령어가 left이면
        }else if("left".equals(direction)){
            if(x-1 < 0) {
                return new int[]{y,x,-1,sum};
            }
            else{
                int cnt=0;
                for(int i=x-1;i>=0;i--){
                    if('D'==board[y].charAt(i)){
                        break;
                    }else{
                        cnt++;
                    }
                }
                return new int[]{y,x-cnt,0,sum+1};
            }
        // 명령어가 right이면
        }else if("right".equals(direction)){
            if(x+1 > board[0].length()-1) {
                return new int[]{y,x,-1,sum};
            }
            else{
                int cnt=0;
                for(int i=x+1;i<board[0].length();i++){
                    if('D'==board[y].charAt(i)){
                        break;
                    }else{
                        cnt++;
                    }
                }
                return new int[]{y,x+cnt,0,sum+1};
            }
        }
        return new int[]{0,0,0,0};
    }
}

 

[실행결과]

728x90