[프로그래머스 - JAVA] 아이템 줍기

2024. 10. 11. 20:57Algorithm

문제 설명

 

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

 

지형은 각 변이 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 이하인 자연수입니다.
    • 지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
  • 캐릭터와 아이템의 처음 위치가 같은 경우는 없습니다.

 

풀이

 

문제의 아이디어 자체는 빠르게 떠올랐지만 이전에 경험하거나 생각해보지 못한 방식이라 문제 이해와 풀이가 어려운 문제였습니다. 이전 문제들을 생각해보면 사각형의 위치를 파악하고 이동했던 했었지만 이 문제에 중요한 점은 테두리이기 때문에 좌표를 2배로 늘려 세부 경로를 탐색할 수 있게 만들어 줘야합니다. 그렇게 되면 해당 좌표 별로 테두리 값을 구할 수 있게 됩니다. 비슷한 유형의 문제로는 프로그래머스에 방문 길이 문제가 있습니다. 

 

프로그래머스 - 방문 길이

 

프로그래머스

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

programmers.co.kr

 

import java.util.*;

class Solution {
    
    static int[][] graph, visited;
    static int[] dx, dy;
    
    public int solution(int[][] rectangles, int characterX, int characterY, int itemX, int itemY) {
        int answer = 0;
        
        graph = new int[102][102];
        visited = new int[102][102];
        
        dx = new int[] {1, -1, 0, 0};
        dy = new int[] {0, 0, 1, -1};

        for (int[] rectangle : rectangles) {
            int x1 = rectangle[0] * 2;
            int y1 = rectangle[1] * 2;
            int x2 = rectangle[2] * 2;
            int y2 = rectangle[3] * 2;
            
            for (int y = y1; y <= y2; y++) {
                for (int x = x1; x <= x2; x++) {
                    // 테투리와 내부 분리
                    if (x == x1 || x == x2 || y == y1 || y == y2) {
                        if (graph[y][x] != 2) {
                            graph[y][x] = 1;
                        }
                    }
                    else {
                        graph[y][x] = 2;
                    }
                }
            }
        }
        
        return bfs(characterX * 2, characterY * 2, itemX * 2, itemY * 2) / 2;
    }
    
    static int bfs(int start_x, int start_y, int t_x, int t_y) {
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[] {start_x, start_y});
        visited[start_y][start_x] = 1;
        
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int x = current[0];
            int y = current[1];
            
            if (x == t_x && y == t_y) {
                return visited[y][x] - 1;
            }
            
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                
                if (0 <= nx && nx < 102 && 0 < ny && ny < 102 && visited[ny][nx] == 0 && graph[ny][nx] == 1) {
                    queue.offer(new int[] {nx, ny});
                    visited[ny][nx] = visited[y][x] + 1;    
                }
                
            }
            
        }
        return 0;
    }
    
}