728x90
조건
- 구슬 탈출은 직사각형 보드에 빨간 구슬과 파란 구슬을 하나씩 넣은 다음, 빨간 구슬을 구멍을 통해 빼내는 게임
- 보드의 세로 크기는 N, 가로 크기는 M이고 편의상 1x1 크기의 칸으로 나눠져있다.
- 가장 바깥 행과 열은 모두 막혀져 있고, 보드에는 구멍이 하나있다.
- 이 때, 파란 구슬이 구멍에 들어가면 안 된다.
- 구슬은 중력을 이용해서 이리 저리 굴려야한다.
- 왼쪽, 오른쪽, 위쪽, 아래쪽으로 기울기이와 같은 네 가지 동작이 가능하다.
- 각각의 동작에서 공은 동시에 움직인다.
- 빨간 구슬이 구멍에 빠지면 성공이지만, 파란 구슬이 구멍에 빠지면 실패
- 빨간, 파란 구슬이 동시에 빠져도 실패
- 빨간 구슬과 파란 구슬은 동시에 같은 칸에 있을 수 없다.
- 기울이는 동작을 그만하는 것은 더 이상 구슬이 움직이지 않을 때 까지이다.
- 보드의 상태가 주어졌을 때, 최소 몇 번만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 구하시오.
입력
- 첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다.
- 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '
.
', '#
', 'O
', 'R
', 'B
' 로 이루어져 있다. - '
.
'은 빈 칸을 의미하고, '#
'은 공이 이동할 수 없는 장애물 또는 벽을 의미하며, 'O
'는 구멍의 위치를 의미한다. 'R
'은 빨간 구슬의 위치, 'B
'는 파란 구슬의 위치이다.
입력되는 모든 보드의 가장자리에는 모두 '#
'이 있다. 구멍의 개수는 한 개 이며, 빨간 구슬과 파란 구슬은 항상 1개가 주어진다.
출력
- 최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 출력한다.
- 만약, 10번 이하로 움직여서 빨간 구슬을 구멍을 통해 빼낼 수 없으면 -1을 출력한다.
접근 방법
- queue에 빨간 구슬의 x, y 좌표, 파란구슬의 x, y 좌표를 넣어준다.
- 방문 여부를 check 배열을 4차원 배열로 선언한다. 배열의 인덱스는 빨간 x, y, 파란 x, y 이다.
- 구슬을 굴리며 다음 위치가 벽이라면 앞으로 가지 못하고 현재 위치가 구멍이라면, 현재 구슬의 색이 무엇인지 판별한다.
- 파란 구슬이라면 무시, 빨간 구슬이라면 cnt 출력
- 구슬을 굴리면서 이동거리를 카운트 해주고, 빨간 구슬과 파란 구슬의 위치가 같다면, 이동 거리를 비교해 겹치지 않게 해준다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from collections import deque
N, M = map(int, input().split())
board = []
for i in range(N):
board.append(list(input().rstrip()))
for j in range(M):
if board[i][j] == 'R':
rx, ry = i, j
elif board[i][j] == 'B':
bx, by = i, j
di, dj = [0,0,1,-1], [1,-1,0,0]
def bfs(rx, ry, bx, by):
visited = [[[[False] * M for _ in range(N)] for _ in range(M)] for _ in range(N)]
q = deque()
q.append((rx, ry, bx, by))
count = 0
while q:
for _ in range(len(q)):
rx, ry, bx, by = q.popleft()
# 움직인 횟수 10회 초과면 -1 출력
if count > 10:
print(-1)
return
# 현재 빨간 구슬위치 구멍이면 count
if board[rx][ry] == 'O':
print(count)
return
# 4방향 탐색
for i in range(4):
nrx, nry = rx, ry
# 벽 또는 구멍을 만날 때까지
while True:
nrx += di[i]
nry += dj[i]
# 벽인 경우 방향 그대로 한칸 뒤로
if board[nrx][nry] == '#':
nrx -= di[i]
nry -= dj[i]
break
if board[nrx][nry] == 'O':
break
nbx, nby = bx, by
while True: # #일 때까지 혹은 구멍일 때까지 움직임
nbx += di[i]
nby += dj[i]
if board[nbx][nby] == '#': # 벽인 경우 왔던 방향 그대로 한칸 뒤로 이동
nbx -= di[i]
nby -= dj[i]
break
if board[nbx][nby] == 'O':
break
# 파란구슬이 먼저 들어가거나 동시에 들어가면 안됨
if board[nbx][nby] == 'O':
continue
# 두 구슬의 위치가 같다면 더 많이 이동한 걸 한칸 물려준다.
if nrx == nbx and nry == nby:
if abs(nrx-rx) + abs(nry-ry) > abs(nbx-bx) + abs(nby -by):
nrx -= di[i]
nry -= dj[i]
else:
nbx -= di[i]
nby -= dj[i]
# 방문 안했다면 추가 후 방문 처리
if not visited[nrx][nry][nbx][nby]:
q.append((nrx, nry, nbx, nby))
visited[nrx][nry][nbx][nby] = True
count += 1
print(-1)
bfs(rx, ry, bx, by)
- 구현 문제 어렵다.. 손코딩 많이 해보고 생각많이 하기
- visited 를 4중 배열로 체크하는 것이 힘들었다 ㅠ
728x90
'ALGORITHM > 정렬, 탐색,구현' 카테고리의 다른 글
[백준 16918번] 파이썬 - 봄버맨 (0) | 2023.03.22 |
---|---|
[백준 14003번] 파이썬 - 가장 긴 증가하는 부분수열 5 (0) | 2023.03.18 |
[백준 14499번] 파이썬 - 주사위 굴리기 (0) | 2023.03.12 |
[백준 10808번] C++ - 알파벳 개수 (0) | 2023.03.02 |
[백준 2143번] 파이썬 - 두 배열의 합 (0) | 2023.02.23 |