| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 27448
- 스펨메일 분류
- dfs
- 코딩테스트
- 모두의 꿈
- BFS
- 정답코드
- 2247
- 구현
- 부분수열의 합2
- 17070
- 코테
- populating next right pointers in each node
- 샤논 엔트로피
- 딥러닝
- python
- T tree
- 정렬
- 백준
- 코딩
- 코복장
- 실질적 약수
- 힙 정렬
- lgb
- 아니메컵
- C
- dp
- ps
- 파이썬
- 다이나믹 프로그래밍
- Today
- Total
코딩복습장
백준: 구슬 탈출 2 (13460번) 본문
https://www.acmicpc.net/problem/13460
| 2 초 | 512 MB | 104295 | 32395 | 18722 | 28.709% |
문제
스타트링크에서 판매하는 어린이용 장난감 중에서 가장 인기가 많은 제품은 구슬 탈출이다. 구슬 탈출은 직사각형 보드에 빨간 구슬과 파란 구슬을 하나씩 넣은 다음, 빨간 구슬을 구멍을 통해 빼내는 게임이다.
보드의 세로 크기는 N, 가로 크기는 M이고, 편의상 1×1크기의 칸으로 나누어져 있다. 가장 바깥 행과 열은 모두 막혀져 있고, 보드에는 구멍이 하나 있다. 빨간 구슬과 파란 구슬의 크기는 보드에서 1×1크기의 칸을 가득 채우는 사이즈이고, 각각 하나씩 들어가 있다. 게임의 목표는 빨간 구슬을 구멍을 통해서 빼내는 것이다. 이때, 파란 구슬이 구멍에 들어가면 안 된다.
이때, 구슬을 손으로 건드릴 수는 없고, 중력을 이용해서 이리 저리 굴려야 한다. 왼쪽으로 기울이기, 오른쪽으로 기울이기, 위쪽으로 기울이기, 아래쪽으로 기울이기와 같은 네 가지 동작이 가능하다.
각각의 동작에서 공은 동시에 움직인다. 빨간 구슬이 구멍에 빠지면 성공이지만, 파란 구슬이 구멍에 빠지면 실패이다. 빨간 구슬과 파란 구슬이 동시에 구멍에 빠져도 실패이다. 빨간 구슬과 파란 구슬은 동시에 같은 칸에 있을 수 없다. 또, 빨간 구슬과 파란 구슬의 크기는 한 칸을 모두 차지한다. 기울이는 동작을 그만하는 것은 더 이상 구슬이 움직이지 않을 때 까지이다.
보드의 상태가 주어졌을 때, 최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 구하는 프로그램을 작성하시오.
입력
첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B' 로 이루어져 있다. '.'은 빈 칸을 의미하고, '#'은 공이 이동할 수 없는 장애물 또는 벽을 의미하며, 'O'는 구멍의 위치를 의미한다. 'R'은 빨간 구슬의 위치, 'B'는 파란 구슬의 위치이다.
입력되는 모든 보드의 가장자리에는 모두 '#'이 있다. 구멍의 개수는 한 개 이며, 빨간 구슬과 파란 구슬은 항상 1개가 주어진다.
출력
최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 출력한다. 만약, 10번 이하로 움직여서 빨간 구슬을 구멍을 통해 빼낼 수 없으면 -1을 출력한다.
예제 입력 1
5 5
#####
#..B#
#.#.#
#RO.#
#####
예제 출력 1
1
예제 입력 2
7 7
#######
#...RB#
#.#####
#.....#
#####.#
#O....#
#######
예제 출력 2
5
예제 입력 3
7 7
#######
#..R#B#
#.#####
#.....#
#####.#
#O....#
#######
예제 출력 3
5
예제 입력 4
10 10
##########
#R#...##B#
#...#.##.#
#####.##.#
#......#.#
#.######.#
#.#....#.#
#.#.#.#..#
#...#.O#.#
##########
예제 출력 4
-1
예제 입력 5
3 7
#######
#R.O.B#
#######
예제 출력 5
1
예제 입력 6
10 10
##########
#R#...##B#
#...#.##.#
#####.##.#
#......#.#
#.######.#
#.#....#.#
#.#.##...#
#O..#....#
##########
예제 출력 6
7
예제 입력 7
3 10
##########
#.O....RB#
##########
예제 출력 7
-1
이 문제는 좀 어려웠다.
약간 피지컬 문제인 것 같다. 내가 구현을 얼마나 잘 할 수 있는가?
풀이 시간은 1시간 30분정도 걸렸다..
bfs로 바로 풀었어야 했는데 dfs를 선택한 것이 큰 문제였다..
이 문제가 bfs로 적합한 이유는 넓게 탐색을 하다 먼저 공이 빠지는 구간을 찾으면 그게 정답이 되기 때문이다.
가장 빨리 빠졌기 때문이라고 볼 수 있다.
문제는 공이 어떻게 이동하는지 구현하는 부분이다.
여기서 이동하는 방향에 따라 한번에 움직여야 한다.
이부분의 구현을 하기 위해 한칸 이후의 구간이 #인지 확인해야 하고 현재 구간이 'o'인지도 학인해야 한다.
따라서 구슬의 이동부분을 함수로 만들었다. (빨간 구슬, 파란 구슬 각각 진행)
그리고 만약 구슬이 구멍에 빠지거나 벽에 붙었을 경우, 좌표와 움직인 거리를 반환해준다.
이 값을 bfs에서 받고 현재 빨간 공의 좌표가 'o'인지 확인, 파란공도 확인
만약 파란공이 빠지면 continue로 while문 loop을 진행해준다.
이 다음 if로 빨간공이 빠졌다 (파란공 안빠짐 빨간공만 빠짐) -> return 결과 count( 필자는 res로 이름 지음) +1
그리고 만약 공의 위치가 겹쳤다면, 같은 좌표에 공이 있을 수 없기 때문에, move함수에서 받은 움직인 거리가 적은 공이
이동방향의 한칸 반대방향에 위치하도록 코드를 짰다.
이후 visited를 4차원으로 짰는데 빨간공 좌표 2차원, 파란공 좌표 2차원 해서 방문한 구간을 기록해주었다.
만약 방문을 하지 않았다면 방문 처리 후에 move로 이동한 현재 좌표를 deque에 추가한다.
이 방식을 계속 반복하면 공은 빠지게 된다.
만약 10번의 반복에도 빠지지 않는다면 함수를 종료하고 -1을 return하면 된다.
아 어렵다 어려워..


구현코드
from collections import deque
def move(x, y, dx, dy, board):
cnt = 0
while board[x + dx][y + dy] != '#' and board[x][y] != 'O':
x += dx
y += dy
cnt += 1
return x, y, cnt
def solve(board, n, m):
visited = [[[[False] * m for _ in range(n)] for _ in range(m)] for _ in range(n)]
for i in range(n):
for j in range(m):
if board[i][j] == 'R':
rx, ry = i, j
if board[i][j] == 'B':
bx, by = i, j
q = deque()
q.append((rx, ry, bx, by, 0))
visited[rx][ry][bx][by] = True
# 방향: 상, 하, 좌, 우
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
while q:
rx, ry, bx, by, depth = q.popleft()
if depth >= 10:
break
for i in range(4):
nrx, nry, r_move = move(rx, ry, dx[i], dy[i], board)
nbx, nby, b_move = move(bx, by, dx[i], dy[i], board)
if board[nbx][nby] == 'O':
continue # 파란 공이 빠지면 안 됨
if board[nrx][nry] == 'O':
return depth + 1 # 빨간 공만 빠지면 성공
if nrx == nbx and nry == nby: # 위치가 같으면 더 많이 이동한 걸 한 칸 뒤로
if r_move > b_move:
nrx -= dx[i]
nry -= dy[i]
else:
nbx -= dx[i]
nby -= dy[i]
if not visited[nrx][nry][nbx][nby]:
visited[nrx][nry][nbx][nby] = True
q.append((nrx, nry, nbx, nby, depth + 1))
return -1
# 입력
n, m = map(int, input().split())
board = [list(input().strip()) for _ in range(n)]
# 출력
print(solve(board, n, m))'코딩 테스트 > python(파이썬)' 카테고리의 다른 글
| LeetCode: Valid Parentheses (0) | 2025.06.03 |
|---|---|
| LeetCode: Maximum Gap (0) | 2025.05.31 |
| LeetCode: Populating Next Right Pointers in Each Node (0) | 2025.05.29 |
| LeetCode: Merge Sorted Array (0) | 2025.05.26 |
| LeetCode: Path Sum II (0) | 2025.05.26 |