본문 바로가기

2024 코딩테스트 스터디

[12주_5일차] 프로그래머스-아이템 줍기(Python)

문제 설명

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

지형은 각 변이 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개인 경우입니다.

 

<코드>

from collections import deque

def solution(rectangle, characterX, characterY, itemX, itemY):
    # 좌표를 2배로 확장 (정밀도를 높이기 위해)
    characterX, characterY, itemX, itemY = characterX * 2, characterY * 2, itemX * 2, itemY * 2
    board = [[0] * 102 for _ in range(102)]
    
    # 직사각형 좌표를 2배로 확장하고 테두리 부분을 표시
    for x1, y1, x2, y2 in rectangle:
        x1, y1, x2, y2 = x1 * 2, y1 * 2, x2 * 2, y2 * 2
        for i in range(x1, x2 + 1):
            for j in range(y1, y2 + 1):
                if x1 < i < x2 and y1 < j < y2:
                    board[i][j] = 2  # 내부는 2로 표시 (다각형 내부)
                elif board[i][j] != 2:
                    board[i][j] = 1  # 테두리면 1로 표시 (외곽선)

    # BFS로 최단 경로 탐색
    def bfs():
        queue = deque([(characterX, characterY, 0)])
        visited = [[False] * 102 for _ in range(102)]
        visited[characterX][characterY] = True
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]  # 상하좌우 방향

        while queue:
            x, y, dist = queue.popleft()

            if x == itemX and y == itemY:
                return dist // 2  # 원래 좌표계로 변환

            for dx, dy in directions:
                nx, ny = x + dx, y + dy

                if 0 <= nx < 102 and 0 <= ny < 102 and not visited[nx][ny] and board[nx][ny] == 1:
                    visited[nx][ny] = True
                    queue.append((nx, ny, dist + 1))

    return bfs()

 

<풀이과정>

 

  • 좌표 2배로 확장:
    • 좌표가 정수로 주어지기 때문에, 두 점 사이의 모든 경로를 고려하기 위해 좌표를 2배로 확장
  • 보드 설정: 각 격자 점에 대해 테두리와 내부를 구분하여 board 배열에 기록
  • 테두리만 확인:
    • 직사각형의 테두리(외곽선)만 따라 이동할 수 있기 때문에, 격자의 각 점에서 그 점이 테두리인지 아닌지를 판별
  • BFS를 이용한 최단 경로 탐색:
    • BFS를 통해 캐릭터의 시작점에서 아이템까지의 최단 경로를 탐색
    • 큐를 이용해 현재 위치에서 이동할 수 있는 모든 테두리 점들을 탐색하고, 해당 점까지의 거리를 계산