문제 설명
다음과 같은 다각형 모양 지형에서 캐릭터가 아이템을 줍기 위해 이동하려 합니다.
지형은 각 변이 x축, y축과 평행한 직사각형이 겹쳐진 형태로 표현하며, 캐릭터는 이 다각형의 둘레(굵은 선)를 따라서 이동합니다.
만약 직사각형을 겹친 후 다음과 같이 중앙에 빈 공간이 생기는 경우, 다각형의 가장 바깥쪽 테두리가 캐릭터의 이동 경로가 됩니다.
단, 서로 다른 두 직사각형의 x축 좌표 또는 y축 좌표가 같은 경우는 없습니다.
즉, 위 그림처럼 서로 다른 두 직사각형이 꼭짓점에서 만나거나, 변이 겹치는 경우 등은 없습니다.
다음 그림과 같이 지형이 2개 이상으로 분리된 경우도 없습니다.
한 직사각형이 다른 직사각형 안에 완전히 포함되는 경우 또한 없습니다.
지형을 나타내는 직사각형이 담긴 2차원 배열 rectangle, 초기 캐릭터의 위치 characterX, characterY, 아이템의 위치 itemX, itemY가 solution 함수의 매개변수로 주어질 때, 캐릭터가 아이템을 줍기 위해 이동해야 하는 가장 짧은 거리를 return 하도록 solution 함수를 완성해주세요.
제한사항
- rectangle의 세로(행) 길이는 1 이상 4 이하입니다.
- rectangle의 원소는 각 직사각형의 [좌측 하단 x, 좌측 하단 y, 우측 상단 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
설명 생략
나의 답
from collections import deque
def solution(rectangle, characterX, characterY, itemX, itemY):
board = [[0] * 102 for _ in range(102)] # 최대 좌표 50 *2=100 -> +2 여유
# 직사각형 2배 확장해서 채우기
for x1, y1, x2, y2 in rectangle:
x1, y1, x2, y2 = x1*2, y1*2, x2*2, y2*2
# 우선 전체를 1로 채워넣기
for x in range(x1, x2+1):
for y in range(y1, y2+1):
board[x][y] = 1
# 내부 부분을 0으로 채우기를 따로 또 수행 1로 채우고 0으로 채우기를 한 반복문 안에서 하면 겹치는 부분에서 오류가 생길 수 있음..!!
for x1, y1, x2, y2 in rectangle:
x1, y1, x2, y2 = x1*2, y1*2, x2*2, y2*2
# 내부 영역을 0으로 넣어서 테두리만 1이도록 처리
for x in range(x1+1, x2):
for y in range(y1+1, y2):
board[x][y] = 0
q = deque()
visited = [[False] * 102 for _ in range(102)]
sx, sy = characterX * 2, characterY * 2
ex, ey = itemX * 2, itemY * 2
q.append((sx, sy, 0))
visited[sx][sy] = True
dx = [0,0,1,-1]
dy = [1,-1,0,0]
while q:
x, y, dist = q.popleft()
if x == ex and y == ey:
return dist // 2
for i in range(4):
nx, ny = x+dx[i], y + dy[i]
if 0<= nx < 102 and 0<= ny < 102:
if not visited[nx][ny] and board[nx][ny] == 1:
visited[nx][ny] = True
q.append((nx, ny, dist + 1))
- 직사각형의 테두리만 따라 이동해야 하는 문제로, 단순 BFS처럼 보여도 전처리가 매우 중요한 문제였다.
- 좌표를 2배로 확장하는 이유는 테두리 간 경계를 정밀하게 표현하기 위해서다. (코너 구분, 대각선 방지 등)
- 처음에는 한번에 테두리와 내부를 동시에 처리하려고 했다가 테스트케이스에서 실패가 떴다. 한 번에 테두리와 내부를 동시에 처리하면, 겹치는 부분에서 테두리가 사라질 수 있기 때문에 두번에 나눠서 전체를 먼저 1로 채운 후, 내부만 0으로 다시 덮어써야 한다.
- 마지막에 거리도 2로 나눠줘야 실제 거리가 나온다는 것도 신경을 꼭 써야한다.
- 처음 문제를 접했을 땐 난이도가 높게 느껴졌고, 그림 없이 머리로만 이해하려 하니 혼란스러웠다.
- 직접 좌표를 2배로 늘려 그림을 그려보며 구조를 이해한 것이 가장 큰 도움이 되었다.
- 결국 어려웠던 이유는 구현 자체보다 경계 처리와 좌표 스케일링의 필요성을 직관적으로 이해하지 못해서였다. 넘무 어렵다..
'공부기록 > TIL' 카테고리의 다른 글
[TIL] 250717 - 프로그래머스 섬 연결하기 (1) | 2025.07.17 |
---|---|
[TIL] 250716 - 프로그래머스 전력망을 둘로 나누기 (0) | 2025.07.16 |
[TIL] 250715 - 프로그래머스 피로도 (0) | 2025.07.15 |
[TIL] 250715 - 프로그래머스 카펫 (0) | 2025.07.15 |
[TIL] 250714 - 프로그래머스 주식 가격 (0) | 2025.07.14 |