Devtraces
개발자취
Devtraces
전체 방문자
오늘
어제
  • 분류 전체보기
    • Baekjoon
    • Programmers

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • programmers
  • two pointer
  • Set
  • Trie
  • prime number
  • recursive
  • level4
  • stack
  • DP
  • binary search
  • Matrix
  • GCD
  • math
  • java
  • BFS
  • map
  • dfs
  • 그리디 알고리즘
  • PriorityQueue
  • Tree
  • 백준
  • greedy
  • level2
  • floyd-warshall
  • level3
  • Queue
  • Kakao
  • sort
  • Dijkstra
  • union-find

최근 댓글

최근 글

티스토리

Devtraces
Programmers

[프로그래머스 Level.3] 아이템 줍기 (깊이/너비 우선 탐색(DFS/BFS)) (Java)

[프로그래머스 Level.3] 아이템 줍기 (깊이/너비 우선 탐색(DFS/BFS)) (Java)
Programmers

[프로그래머스 Level.3] 아이템 줍기 (깊이/너비 우선 탐색(DFS/BFS)) (Java)

2023. 3. 28. 19:25

문제 링크

https://school.programmers.co.kr/learn/courses/30/lessons/87694

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

 

 

 

코딩테스트 연습 > 깊이/너비 우선 탐색(DFS/BFS) > 아이템 줍기

 

 

 

문제 설명

 

 

다음과 같은 다각형 모양 지형에서 캐릭터가 아이템을 줍기 위해 이동하려 합니다.

 

 

지형은 각 변이 x축, y축과 평행한 직사각형이 겹쳐진 형태로 표현하며, 캐릭터는 이 다각형의 둘레(굵은 선)를 따라서 이동합니다.

 

만약 직사각형을 겹친 후 다음과 같이 중앙에 빈 공간이 생기는 경우, 다각형의 가장 바깥쪽 테두리가 캐릭터의 이동 경로가 됩니다.

 

 

단, 서로 다른 두 직사각형의 x축 좌표 또는 y축 좌표가 같은 경우는 없습니다.

 

 

즉, 위 그림처럼 서로 다른 두 직사각형이 꼭짓점에서 만나거나, 변이 겹치는 경우 등은 없습니다.

 

다음 그림과 같이 지형이 2개 이상으로 분리된 경우도 없습니다.

 

 

한 직사각형이 다른 직사각형 안에 완전히 포함되는 경우 또한 없습니다.

 

 

지형을 나타내는 직사각형이 담긴 2차원 배열 rectangle, 초기 캐릭터의 위치 characterX, characterY, 아이템의 위치 itemX, itemY가 solution 함수의 매개변수로 주어질 때, 캐릭터가 아이템을 줍기 위해 이동해야 하는 가장 짧은 거리를 return 하도록 solution 함수를 완성해주세요.

 

 

 

제한사항
  • rectangle의 세로(행) 길이는 1 이상 4 이하입니다.
  • rectangle의 원소는 각 직사각형의 [좌측 하단 x, 좌측 하단 y, 우측 상단 x, 우측 상단 y] 좌표 형태입니다.
    • 직사각형을 나타내는 모든 좌표값은 1 이상 50 이하인 자연수입니다.
    • 서로 다른 두 직사각형의 x축 좌표, 혹은 y축 좌표가 같은 경우는 없습니다.
    • 문제에 주어진 조건에 맞는 직사각형만 입력으로 주어집니다.
  • charcterX, charcterY는 1 이상 50 이하인 자연수입니다.
    • 지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
  • itemX, itemY는 1 이상 50 이하인 자연수입니다.
    • 지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
  • 캐릭터와 아이템의 처음 위치가 같은 경우는 없습니다.

 


 

  • 전체 배점의 50%는 직사각형이 1개인 경우입니다.
  • 전체 배점의 25%는 직사각형이 2개인 경우입니다.
  • 전체 배점의 25%는 직사각형이 3개 또는 4개인 경우입니다.

 


 

입출력 예
rectangle characterX characterY itemX itemY result
[[1,1,7,4],[3,2,5,5],[4,3,6,9],[2,6,8,8]] 1 3 7 8 17
[[1,1,8,4],[2,2,4,9],[3,6,9,8],[6,3,7,7]] 9 7 6 1 11
[[1,1,5,7]] 1 1 4 7 9
[[2,1,7,5],[6,4,10,10]] 3 1 7 10 15
[[2,2,5,5],[1,3,6,4],[3,1,4,6]] 1 4 6 3 10
 

 

 
입출력 예 설명

 

 

입출력 예 #1

 

 

캐릭터 위치는 (1, 3)이며, 아이템 위치는 (7, 8)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.

 

 

 

 

입출력 예 #2

 

 

캐릭터 위치는 (9, 7)이며, 아이템 위치는 (6, 1)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.

 

 

 

 

입출력 예 #3

 

 

캐릭터 위치는 (1, 1)이며, 아이템 위치는 (4, 7)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.

 

 

 

 

입출력 예 #4, #5

 

 

 

 

 

 

나의 코드

import java.util.*;

class Solution {
    static int[] dx = {-1, 1, 0, 0};
    static int[] dy = {0, 0, -1, 1};
    int[][] matrix;
    boolean[][] visited;
    public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
        int answer = 0;
        
        matrix = new int[102][102];
        visited = new boolean[102][102];
        
        for(int i=0; i<rectangle.length; i++) {
            int x1 = rectangle[i][0] * 2;
            int y1 = rectangle[i][1] * 2;
            int x2 = rectangle[i][2] * 2;
            int y2 = rectangle[i][3] * 2;
            
            for(int j=y1; j<=y2; j++) {
                for(int k=x1; k<=x2; k++) {
                    matrix[j][k] = 1;
                }
            }
        }
        
        for(int i=0; i<rectangle.length; i++) {
            int x1 = rectangle[i][0] * 2;
            int y1 = rectangle[i][1] * 2;
            int x2 = rectangle[i][2] * 2;
            int y2 = rectangle[i][3] * 2;
            
            for(int j=y1+1; j<y2; j++) {
                for(int k=x1+1; k<x2; k++) {
                    matrix[j][k] = 0;
                }
            }
        }

        int result = bfs(characterX * 2, characterY * 2, itemX * 2, itemY * 2);
        
        answer = result / 2;
        
        return answer;
    }
    
    public int bfs(int cX, int cY, int iX, int iY) {
        Queue<Node> q = new LinkedList<>();
        q.add(new Node(cX, cY, 0));
        
        while(!q.isEmpty()) {
            Node node = q.poll();
            
            if(node.x == iX && node.y == iY) {
                System.out.println("node.X=" + node.x + "/ node.Y=" + node.y);
                return node.cnt;
            }
                
            for(int i=0; i<4; i++) {
                int nx = node.x + dx[i];
                int ny = node.y + dy[i];
                
                if(nx < 0 || ny < 0 || visited[ny][nx] || matrix[ny][nx] != 1) continue;   
                
                visited[ny][nx] = true;
                q.add(new Node(nx, ny, node.cnt+1));
            }
        }
        
        return -1;
    }
    
    public class Node {
        int x;
        int y;
        int cnt;
        
        public Node(int x, int y, int cnt) {
            this.x = x;
            this.y = y;
            this.cnt = cnt;
        }
    }
}

 

풀이

  1. 주어진 사각형을 1로 그린 후에 테두리의 값만 1로 남겨두고 내부는 0으로 다사 채운 후에 시작 좌표에서 완전탐색 bfs를 이용하여 아이템이 있는 좌표까지의 최단거리를 구하면 된다.
  2. 하지만 여기서 중요한 점은 bfs를 진행할 때 자칫하면 좌표의 거리가 1인 ㄷ자 모양의 테두리가 있을 때 ㅁ자 모양으로 오해하여 이동할 수 있다.
  3. 예를들어, 첫 번째 그림에서 좌표 (3, 5) (4, 5), (4,6), (3, 6)을 보면 ㄷ자 반대 모양으로 각각 거리가 1로 패여있는 부분에서 bfs를 좌표가 (3,5)에서 진행할 때 오른쪽 좌표 (4, 5)로 이동할 수도 있고 위쪽 좌표 (3, 6)으로 이동 할 수 도있다.
    하지만 (3, 6)으로 이동하는 것은 테두리가 없기 때문에 이동하면 안되기 때문에 막아주어야 한다. 
  4. 만약 0.5씩 이동한다고 하면 위쪽으로는 이동을 할 수 없고 오른쪽으로만 이동이 가능하다. 따라서 0.5씩 계산을 하기는 상당히 까다로우므로 좌표를 2배로 확대하여 풀면 된다.
  5. 좌표를 2배로 확대하여 나타낼 2차원 배열 matrix와 좌표 방문 테이블로 사용할 visited를 각각 행과 열의 길이를 102로 하여 생성한다. (행과 열의 기존 길이가 1 이상 50 이하로 51길이로 나타내기 때문에 2배 하면 102이다)
  6. 이제 주어진 rectangle을 순회하면서 직사각형의 네 좌표를 받아와 각각 2배로 하여 해당 직사각형 모양의 matrix 좌표에 모두 1로 저장한다.
  7. 그리고 다시 rectangle을 순회하면서 직사각형의 네 좌표를 받아와 각각 2배로 한 다음 상하좌우 테두리 부분만 남겨두고 위아래로 1씩 줄이고 좌우로 1씩 줄여 직사각형 내부의 부분에 해당하는 matrix의 값을 모두  0으로 저장한다. (처음에 rectangle을 순회하면서 직사각형 모양으로 모두 1씩 저장하고 다시 rectangle을 순회하면서 해야지 겹치는 직사각형의 내부에 해당하는 한 직사각형의 테두리 부분들을 모두 0으로 변경할 수 있다)
  8. 이제 캐릭터의 출발 좌표와 아이템의 좌표도 각각 2배로 하여 완전탐색 bfs를 진행하여 matrix 값이 1로 되어있는 테두리 부분으로만 이동하여 최소 이동 거리를 구한 다음 좌표를 2배로 한 것이기 때문에 2로 나누어주어 answer에 저장하고 반환하면 된다. (테두리 부분으로만 이동하기 때문에 결국 캐릭터 위치에서 좌 or 우나 상 or 하로 이동하는 2가지 경우 중에 더 짧게 이동하는 것을 구하는 것이다)

 

 

참고 : https://school.programmers.co.kr/questions/21253

'Programmers' 카테고리의 다른 글

[프로그래머스 Level.3] 파괴되지 않은 건물 (2022 KAKAO BLIND RECRUITMENT) (Java)  (0) 2023.03.30
[프로그래머스 Level.3] 합승 택시 요금 (2021 KAKAO BLIND RECRUITMENT) (Java)  (0) 2023.03.29
[프로그래머스 Level.2] 광물 캐기 (연습 문제) (Java)  (0) 2023.03.28
[프로그래머스 Level.2] 당구 연습 (연습 문제) (Java)  (0) 2023.03.27
[프로그래머스 Level.3] 광고 삽입 (2021 KAKAO BLIND RECRUITMENT) (Java)  (0) 2023.03.24
  • 문제 링크
  • 코딩테스트 연습 > 깊이/너비 우선 탐색(DFS/BFS) > 아이템 줍기
  • 나의 코드
  • 풀이
'Programmers' 카테고리의 다른 글
  • [프로그래머스 Level.3] 파괴되지 않은 건물 (2022 KAKAO BLIND RECRUITMENT) (Java)
  • [프로그래머스 Level.3] 합승 택시 요금 (2021 KAKAO BLIND RECRUITMENT) (Java)
  • [프로그래머스 Level.2] 광물 캐기 (연습 문제) (Java)
  • [프로그래머스 Level.2] 당구 연습 (연습 문제) (Java)
Devtraces
Devtraces

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.