티스토리 뷰
https://www.acmicpc.net/problem/1520
- 문제 :
여행을 떠난 세준이는 지도를 하나 구하였다. 이 지도는 아래 그림과 같이 직사각형 모양이며 여러 칸으로 나뉘어져 있다. 한 칸은 한 지점을 나타내는데 각 칸에는 그 지점의 높이가 쓰여 있으며, 각 지점 사이의 이동은 지도에서 상하좌우 이웃한 곳끼리만 가능하다.
현재 제일 왼쪽 위 칸이 나타내는 지점에 있는 세준이는 제일 오른쪽 아래 칸이 나타내는 지점으로 가려고 한다. 그런데 가능한 힘을 적게 들이고 싶어 항상 높이가 더 낮은 지점으로만 이동하여 목표 지점까지 가고자 한다. 위와 같은 지도에서는 다음과 같은 세 가지 경로가 가능하다.'
지도가 주어질 때 이와 같이 제일 왼쪽 위 지점에서 출발하여 제일 오른쪽 아래 지점까지 항상 내리막길로만 이동하는 경로의 개수를 구하는 프로그램을 작성하시오.
- 풀이 :
BFS로 해결할 수 있다.
처음엔 board의 값이 더 작은 위치로만 이동할 수 있기 때문에 visited를 사용하지 않고 해결하려 했다. visited로 방문여부를 체크하지 않아도 중복되는 루트는 생기겠지만 루프는 생기지 않기 때문이다.
바로 시간초과에 걸려서 중복된 루트로 가지 않는 방법을 생각해야 했다.
해답은 우선순위 큐를 사용하는 것이었다.
우선순위 큐를 max heap으로 사용하여 탐색하려는 노드의 높이가 높은 순서대로 탐색한다. 이 때, visited가 0 (초깃값) 이라면 처음 탐색하는 것이므로 우선순위 큐에 해당 좌표를 넣어주고 이후에 탐색하게 한다.
만약 visited가 0이 아니라면 이미 현재 탐색하는 높이보다 큰 높이에서 탐색을 진행한 것이므로 현재 높이에서 탐색해도 의미가 없다. 즉, 중복된 루트이다. 따라서 중복된 루트는 탐색은 진행하지 않고 visited의 카운트만 증가시켜주어 경로의 개수만 세어주면 된다.
- 소스코드 :
from collections import deque
import heapq as hq
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
N,M = map(int,input().split())
board = [list(map(int,input().split())) for _ in range(N)]
visited = [[0]*M for _ in range(N)]
queue = []
visited[0][0] = 1
hq.heappush(queue,[-board[0][0],0,0])
while queue:
curr,x,y = hq.heappop(queue)
curr = -curr
for i in range(4):
ax = x + dx[i]
ay = y + dy[i]
if 0 <= ax < N and 0 <= ay < M:
if board[x][y] > board[ax][ay]:
if visited[ax][ay] == 0:
hq.heappush(queue, (-board[ax][ay], ax, ay))
visited[ax][ay] += visited[x][y]
print(visited[N-1][M-1])
'Algorithm > DFS & BFS' 카테고리의 다른 글
(Python) - BOJ(1261번) : 알고스팟 (0) | 2022.03.08 |
---|---|
(Python) - BOJ(13549번) : 숨바꼭질 3 (0) | 2022.03.04 |
(Python) - BOJ(1967번) : 트리의 지름 (0) | 2022.03.03 |
(Python) - BOJ(11725번) : 트리의 부모 찾기 (0) | 2022.03.03 |
(Python) - BOJ(2206번) : 벽 부수고 이동하기 (0) | 2022.03.02 |