반응형
해당 포스팅의 문제의 출처는 나동빈님의 이것이 취업을 위한 코딩 테스트 교재를 공부하면서 풀이할 때 본인의 사고 과정 흐름과 문제 풀이를 기록하기 위함 입니다.
문제설명
하단의 링크를 참조하자.
https://programmers.co.kr/learn/courses/30/lessons/60063
사고과정
- 로봇 좌표를 하나의 노드, 로봇의 좌표들 간의 비용을 이동하는 데 걸리는 시간(1)으로 간선으로 하여 모든 간선의 비용이 동일할 때 최솟값을 찾는 전형적인 BFS 문제라고 한다.
- 매우 어려웠고 풀지 못했음.. 코드에 좌표를 하나씩 써가면서 풀이를 써놓았으니 소스코드를 참고하는 게 좋을 듯하다.
- 문제풀이의 큰 단계는 다음과 같다. 가장 핵심적인 것은 큐에는 로봇좌표와 간선 비용을 넣는다는 점(이 때 간선 비용을 넣을 때마다 +1 해준다)과 로봇이 이동하거나 회전할 수 있는 경우의 수를 직접 생각해서 그림을 그려봐야 알 수 있다.
- # 1. 맵 정보 벗어나는 걸 간단하게 처리하기 위해 맵 외곽에 벽을 추가로 설치해 늘리기
# 2. BFS를 활용해야 함. 큐에는 (로봇의 좌표값들, 시간) 형태로 원소를 집어넣음
# 3. 로봇이 이동 또는 회전이 가능한 경우의 수는 다음과 같음
# 3-1. 이동하는 경우 -> 상,하,좌,우 이동했을 때, 로봇의 좌표에 있는 값들이 모두 0일 경우
# 3-2. 회전하는 경우
# 3-2-1. 로봇이 가로로 되어 있을 경우 -> 로봇 좌표를 기준으로 모두 행+1,-1했을 때 모두 0일 경우가능
# 3-2-2. 로봇이 세로로 되어 있을 경우 -> 로봇 좌표를 기준으로 모두 열+1,-1했을 때 모두 0일 경우가능
풀이(스스로 못 푼 풀이)
from collections import deque
def move_robot(pos: set, board):
pos_list = [] # 로봇이 이동가능한 좌표들 담을 리스트
# 현재 로봇 위치 좌표 값
pos = list(pos)
pos_x1, pos_y1, pos_x2, pos_y2 = pos[0][0], pos[0][1], pos[1][0], pos[1][1]
# 3-1.이동하는 경우
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
for i in range(4):
pos_next_x1, pos_next_y1, pos_next_x2, pos_next_y2 = pos_x1 + dx[i], pos_y1 + dy[i], pos_x2 + dx[i], pos_y2 + \
dy[i]
# 로봇의 좌표에 있는 값들이 모두 0일 경우에는 이동 가능
if board[pos_next_x1][pos_next_y1] == 0 and board[pos_next_x2][pos_next_y2] == 0:
pos_list.append({(pos_next_x1, pos_next_y1), (pos_next_x2, pos_next_y2)})
# 3-2.회전하는 경우
# 3-2-1. 로봇이 가로로 있는 경우(로봇의 두 좌표 x값이 같을 때)
if pos_x1 == pos_x2:
# 위(-1), 아래(+1) 이동하는 경우
for i in [-1, 1]:
if board[pos_x1 + i][pos_y1] == 0 and board[pos_x2 + i][pos_y2] == 0:
pos_list.append({(pos_x1, pos_y1), (pos_x1 + i, pos_y1)})
pos_list.append({(pos_x2, pos_y2), (pos_x2 + i, pos_y2)})
# 3-2-2. 로봇이 세로로 있는 경우(로봇의 두 좌표 y값이 같을 때)
elif pos_y1 == pos_y2:
# 왼쪽(-1), 오른쪽(+1) 이동하는 경우
for i in [-1, 1]:
if board[pos_x1][pos_y1 + i] == 0 and board[pos_x2][pos_y2 + i] == 0:
pos_list.append({(pos_x1, pos_y1), (pos_x1, pos_y1 + i)})
pos_list.append({(pos_x2, pos_y2), (pos_x2, pos_y2 + i)})
# 로봇이 갈 수 있는 위치 좌표 리스트 return
return pos_list
def solution(board):
# 1. 맵 길이를 늘리기
n = len(board)
new_board = [[1] * (n + 2) for _ in range(n + 2)]
for i in range(n):
for j in range(n):
new_board[i + 1][j + 1] = board[i][j]
robot_queue = deque([]) # 로봇 좌표와 시간을 담는 큐 정의
visited = [] # 로봇이 거쳐간 맵 좌표들 기록(방문 처리용 리스트)
# 로봇의 초기 위치 정보 넣기
pos = {(1, 1), (1, 2)}
robot_queue.append((pos, 0))
visited.append(pos)
# 큐가 빌 때까지 BFS 탐색
while robot_queue:
pos, cost = robot_queue.popleft()
# 로봇 위치 좌표 중 하나가 (n, n) 좌표에 도달했다면 종료
if (n, n) in pos:
return cost
# 큐에서 꺼낸 로봇 위치에서 갈 수 있는 곳 탐색
for next_pos in move_robot(pos, new_board):
if next_pos not in visited:
visited.append(next_pos)
robot_queue.append((next_pos, cost + 1))
return cost
다음날 혼자 다시 풀어본 풀이
from collections import deque
def move_robot(pos: set, board):
next_pos_lst = []
pos = list(pos) # 인덱싱 가능케하기 위해
pos_x1, pos_y1, pos_x2, pos_y2 = pos[0][0], pos[0][1], pos[1][0], pos[1][1]
# 1.로봇이 이동가능한지 먼저 탐색
dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]
for i in range(4):
next_pos_x1, next_pos_y1, next_pos_x2, next_pos_y2 = pos_x1+dx[i], pos_y1+dy[i], pos_x2+dx[i], pos_y2+dy[i]
if board[next_pos_x1][next_pos_y1] == 0 and board[next_pos_x2][next_pos_y2] == 0:
next_pos_lst.append({(next_pos_x1, next_pos_y1), (next_pos_x2, next_pos_y2)})
# 2-1.로봇이 회전하는 경우 -> 로봇이 가로로 있을 때
if pos_x1 == pos_x2:
# 위, 아래
for i in [-1, 1]:
if board[pos_x1+i][pos_y1] == 0 and board[pos_x2+i][pos_y2] == 0:
next_pos_lst.append({(pos_x1, pos_y1), (pos_x1+i, pos_y1)})
next_pos_lst.append({(pos_x2, pos_y2), (pos_x2+i, pos_y2)})
# 2-2.로봇이 회전하는 경우 -> 로봇이 세로로 있을 때
elif pos_y1 == pos_y2:
# 위, 아래
for i in [-1, 1]:
if board[pos_x1][pos_y1+i] == 0 and board[pos_x2][pos_y2+i] == 0:
next_pos_lst.append({(pos_x1, pos_y1), (pos_x1, pos_y1+i)})
next_pos_lst.append({(pos_x2, pos_y2), (pos_x2, pos_y2+i)})
return next_pos_lst
def solution(board):
n = len(board)
# 외곽에 벽 추가로 설치 -> 0은 갈 수 있는 칸이므로 벽인 1로 해야함!!
new_board = [[1] * (n+2) for _ in range(n+2)]
for i in range(n):
for j in range(n):
new_board[i+1][j+1] = board[i][j]
pos_q = deque([]) # 로봇 좌표와 비용을 담을 큐 정의
visited = [] # 방문한 로봇 좌표 담을 리스트
# 초기 로봇 좌표
pos = {(1, 1), (1, 2)}
pos_q.append((pos, 0))
visited.append(pos)
# 큐가 빌 때까지 반복
while pos_q:
pos, time = pos_q.popleft()
# 현재 로봇 좌표 중 하나가 (n, n)에 닿았다면 끝!
if (n, n) in pos:
break
# 현재 로봇 좌표 기준으로 로봇이 이동할 수 있는 좌표들 BFS 탐색
for next_pos in move_robot(pos, new_board):
if next_pos not in visited:
visited.append(next_pos) # 방문처리
pos_q.append((next_pos, time+1)) # 이동가능 로봇 좌표랑 시간+1 해서 큐에 다시 넣기
return time
반응형
'알고리즘 삽질장' 카테고리의 다른 글
[BOJ] 9093번 - 단어 뒤집기 (0) | 2021.10.23 |
---|---|
[BOJ] 10828번 - 스택 (0) | 2021.10.23 |
[이코테] DFS/BFS - 인구 이동 (0) | 2021.10.21 |
[이코테] 구현 - 외벽 점검 (0) | 2021.10.21 |
[이코테] 그래프 알고리즘 - 최종 순위 (0) | 2021.10.20 |