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

유콩·2023년 6월 16일
0

코딩테스트

목록 보기
23/25
post-thumbnail

문제 설명

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

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

입출력 예

rectanglecharacterXcharacterYitemXitemYresult
[[1,1,7,4],[3,2,5,5],[4,3,6,9],[2,6,8,8]]137817
[[1,1,8,4],[2,2,4,9],[3,6,9,8],[6,3,7,7]]976111
[[1,1,5,7]]11479
[[2,1,7,5],[6,4,10,10]]3171015
[[2,2,5,5],[1,3,6,4],[3,1,4,6]]146310

입출력 예 설명

입출력 예 #1

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

입출력 예 #2

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

입출력 예 #3

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

입출력 예 #4, #5

설명 생략


여러 직사각형이 있을 때 테두리만 거쳐가면서 최종 목적지까지의 최단거리를 구하는 문제이다.

처음에는 좌표값으로 이루어져 있어 단순 반복문으로 풀기보다 재귀함수를 이용하는 편이 간단하다고 생각하여 DFS 로 풀이하였으나, 주어진 메모리보다 스택이 오버되어 실패되었다. 따라서 DFS 보다 속도가 빠른 BFS 로의 풀이 방법을 찾아보았다.

좌표값을 기준으로 순회하기 위해 좌표를 표현하는 2차원 리스트(field)를 생성하고, 테두리일 경우 요소의 값을 1로 변경하여 테투리와 내부를 구분지었다. 주어진 리스트를 인덱스 순서대로 순회하는 것이 아닌 좌표값을 기준으로 상하좌우 이동해야 하기 때문에 좌표 2차원 리스트에서 이전 좌표에서의 최단거리 누적합을 구해 최종 최단거리를 구한다.

하지만 좌표를 2차원 리스트로 그려보면 다음과 같은 문제가 발생한다. 숫자 2와 같은 모양으로 되어있는 선을 그린다고 가정할 때,

111
111
111

리스트상으로는 좌표 간에 연결이 사라져 이를 구분하기 어려워진다. 이를 위해 field 를 2배수로 그려준다.

111111111
1
1
1
111111111
1
1
1
111111111

좌표값을 2배수로 그렸기 때문에 결과를 반환할 때 2를 나눈값을 반환한다.

Code

from collections import deque

def solution(rectangle, characterX, characterY, itemX, itemY):
    field = [[-1] * 102 for _ in range(102)]
    
    for rec in rectangle:
        x1, y1, x2, y2 = map(lambda x: x * 2, rec)
        for x in range(x1, x2 + 1):
            for y in range(y1, y2 + 1):
                if x1 < x < x2 and y1 < y < y2:
                    field[y][x] = 0
                elif field[y][x] != 0:
                    field[y][x] = 1
    
    dx, dy = [-1, 1, 0, 0], [0, 0, -1, 1]
    visited = [[False] * 102 for _ in range(102)]
    
    q = deque()
    q.append([characterX * 2, characterY * 2])
    visited[characterY * 2][characterX * 2] = True
    
    while q:
        x, y = q.popleft()
        if x == itemX * 2 and y == itemY * 2:
            return field[y][x] // 2
        
        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            
            if visited[ny][nx] or field[ny][nx] != 1:
                continue
            
            field[ny][nx] = field[y][x] + 1
            q.append([nx, ny])
            visited[ny][nx] = True
    return 0

0개의 댓글

관련 채용 정보