14442번: 벽 부수고 이동하기 2
첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.
www.acmicpc.net
문제
N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다.
만약에 이동하는 도중에 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 K개 까지 부수고 이동하여도 된다.
한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.
맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.
입력
첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.
출력
첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.
코드
from collections import deque
import sys
input = sys.stdin.readline
def bfs(map_data):
dx = [0, 0, -1, 1]
dy = [-1, 1, 0, 0]
visited = [[k+1]*m for _ in range(n)] # 해당 칸까지 최단 거리로 올 때 부순 벽의 최소 개수
visited[0][0] = 0
q = deque([(0, 0, 1)])
while q:
x, y, cnt = q.popleft()
if x == n-1 and y == m-1:
return cnt
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < n and 0 <= ny < m:
if visited[x][y]+map_data[nx][ny] < visited[nx][ny]:
visited[nx][ny] = visited[x][y]+map_data[nx][ny]
q.append((nx, ny, cnt+1))
return -1
n, m, k = map(int, input().split())
map_data = []
for i in range(n):
map_data.append(list(map(int, input().strip())))
print(bfs(map_data))
기본적인 BFS를 조금 변형해서 풀었다. 이미 방문한 칸인지 확인하는 visited 배열에 해당 칸까지 최단 거리로 올 때 부순 벽의 최소 개수를 저장하도록 한다. 탐색하며 다음 칸(nx, ny)의 visited[nx][ny] 값이 visited[x][y] + map_data[nx][ny]보다 크다면 현재 칸(x, y)에서 다음 칸으로 갈 때 더 적게 벽을 부수며 갈 수 있다는 것이다. 이때 map_data[nx][ny]를 더해주는 이유는 이동할 수 있는 칸은 0, 벽은 1로 표시되어 있기 때문에 해당 칸이 벽이었다면 1이 더해지게 되어서 해당 칸까지 오며 부순 벽의 개수를 셀 수 있기 때문이다.
PyPy3로 통과 가능하다. 이미 제출한 사람들을 봐도 Python3로는 통과할 수 있는 방법이 없는 것 같다
'문제풀이 > DFS_BFS' 카테고리의 다른 글
[Python/파이썬] 백준 13913번 숨바꼭질 4 (0) | 2023.10.09 |
---|---|
[Python/파이썬] 백준 1240번 노드사이의 거리 (0) | 2023.09.25 |
[Python/파이썬] 백준 번 직사각형 탈출 (0) | 2023.09.05 |
[Python/파이썬] 백준 16988번 Baaaaaaaaaduk2 (Easy) (0) | 2023.08.31 |
[Python/파이썬] 백준 3980번 선발 명단 (0) | 2023.08.27 |