728x90
시간 제한 5초(추가 시간 x), 메모리 제한 1024MB(추가 메모리 x)
# 조건
- 고양이 도도가 강아지들을 피해 탈출구를 찾아 방을 탈출하려 하고 있다.
- 고양이 도도는 현재 위치한 공간의 상태에 따라 다음과 같이 움직일 수 있다.
- 고양이가 위치한 곳에 사다리가 존재하거나 고양이가 위치한 곳이 아래가 뚫려있는 공간이 아닌 상태에서 고양이가 위치한 곳의 아래 칸에 사다리가 존재한다면 각각 위 칸과 아래 칸으로 이동할 수 있고 사다리를 이용하여 한 칸 이동할 시 5만큼의 체력이 소모된다.
- 고양이가 위치한 곳이 아래가 뚫려 있는 공간이라면 고양이는 아래에 있는 바닥 중 가장 처음 마주한 바닥에 착지하게 되며 이때 10만큼의 체력이 소비된다.
- 고양이가 아래가 뚫려 있는 공간에 위치해 있지 않을 경우, 좌우로 1칸씩 이동할 수 있으며 1칸 이동할 시 1만큼의 체력이 소비된다.
- 이 때, 평평한 바닥 위에서의 이동과 사다리 타기, 바닥으로 착지하는 행동은 별개의 행동으로 본다.
- 예시로 고양이 도도가 사다리가 있는 위치로 1칸 이동한 후 사다리를 타고 1칸을 올라간다면 총 6만큼의 체력이 소비된다.
- 고양이 도도가 체력을 가장 적게 소비하며 탈출하고자 할 때 고양이 도도는 얼마의 체력으로 탈출할 수 있을까?
입력
- 첫째 줄에 방의 높이 N(2<=N<=1000)과 방의 너비 M(2<=M<=1000)이 주어진다.
- 둘째 줄부터 N개의 줄에 공간의 상태가 주어진다.
- 공간의 상태는 C, D, E, F, L, X로 이루어져 있고, 아래와 같은 의미를 가진다.
- C: 고양이 도도
- D: 강아지
- E: 탈출구
- F: 일반 바닥
- L: 사다리
- X: 아래가 뚫려있는 공간
- 고양이와 탈출구는 방안에 각각 하나씩 있으며 아래가 뚫려있는 공간을 제외하고는 모든 위치에 평평한 바닥이 존재한다.
- 가장 아래 바닥의 경우에는 아래가 뚫려 있는 공간이 올 수 없다.
출력
- 고양이 도도가 체력을 가능한 적게 소비하며 방을 탈출하려 할 때, 총 얼마의 체력으로 방을 탈출할 수 있을지 소비된 체력을 출력한다.
- 방을 탈출하지 못할 경우에는 dodo sad를 출력한다.
# 접근 방법
- bfs를 돌려 출구에 도착하는 모든 곳을 비교해준다면 시간초과가 발생한다.
- 다익스트라와 딕셔너리를 활용하여 시간을 줄여줄 필요가 있다.
- 우선 고양이가 출발하는 위치와 도착위치, 사다리 위치와 내려간 지점 또는 올라가는 지점, 낙하시 도착 지점을 기록해준다.
- bfs를 돌리는데 우선순위 큐를 이용하여, 소비되는 체력을 기준으로 넣어준다.
- 또한, 방문 한 경우 현재 기록된 cnt가 visited에 기록된 값 보다 크다면 continue 해준다.
- 주의해야 될 점은 사다리가 있는 칸인 경우 올라가는 것은 선택이다.
- 내려오는 경우도..
- 또한, 시작 위치에 사다리가 있는 경우도 고려하지 않았다.. 항상 출발위치 찾고 땅과 같이 일반적인 경우로 변경해주기.. !
시간 초과
- 매번 체크하는 과정을 반복해주니 시간 초과가 발생하였다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from heapq import heappush, heappop
INF = float('inf')
def dijkstra(ci, cj):
q = [(0, ci, cj)]
visited[ci][cj] = 0
while q:
val, si, sj = heappop(q)
if arr[si][sj] == 'E':
print(val)
return
if visited[si][sj] < val:
continue
# 평지인 경우 현재 위치에서 내려갈 수 있는 사다리 있는지 체크
# 좌우 체크
if arr[si][sj] == 'F':
for j in [-1, 1]:
ni, nj = si, sj + j
if 0<=nj<M and arr[ni][nj] != 'D':
if visited[ni][nj] > val + 1:
visited[ni][nj] = val + 1
heappush(q, (val+1, ni, nj))
# 사다리 있는지 체크
if (si, sj) in fall_ladder:
ni, nj = fall_ladder[(si, sj)]
if visited[ni][nj] > val + 5:
visited[ni][nj] = val+5
heappush(q, (val+5, ni, nj))
# 사다리인 경우
# 올라가는 경우와 내려갈 수 있는 경우, 좌우 체크
elif arr[si][sj] == 'L':
for j in [-1, 1]:
ni, nj = si, sj + j
if 0 <= nj < M and arr[ni][nj] != 'D':
if visited[ni][nj] > val + 1:
visited[ni][nj] = val+1
heappush(q, (val + 1, ni, nj))
# 사다리 있는지 체크
if (si, sj) in climb_ladder:
ni, nj = climb_ladder[(si, sj)]
if visited[ni][nj] > val + 5:
visited[ni][nj] = val+5
heappush(q, (val + 5, ni, nj))
# 사다리 있는지 체크
if (si, sj) in fall_ladder:
ni, nj = fall_ladder[(si, sj)]
if visited[ni][nj] > val + 5:
visited[ni][nj] = val + 5
heappush(q, (val + 5, ni, nj))
# 바닥이 없는경우
# 떨어지고 나서 사다리가 있는지 체크
elif arr[si][sj] == 'X':
if (si, sj) in fall:
ni, nj = fall[(si,sj)]
if visited[ni][nj] > val + 10:
visited[ni][nj] = val + 10
heappush(q, (val + 10, ni, nj))
print('dodo sad')
return
N, M = map(int, input().split())
arr = [list(input().rstrip()) for _ in range(N)]
fall_ladder = dict()
climb_ladder = dict()
fall = dict()
# 순회하며 출발, 도착 위치와
# 사다리를 타고 올라가는 경우, 내려오는 경우
# 떨어지는 곳이라면 낙하지점을 기록해준다.
for i in range(N):
for j in range(M):
if arr[i][j] == 'C':
ci, cj = i, j
arr[i][j] = 'F'
elif arr[i][j] == 'E':
ei, ej = i, j
elif arr[i][j] == 'L':
# 올라간 곳이 땅 또는 사다리이면 기록
if 0<= i-1 and arr[i - 1][j] != 'X' and arr[i - 1][j] != 'D':
fall_ladder[(i-1, j)] = (i, j)
climb_ladder[(i, j)] = (i-1, j)
elif arr[i][j] == 'X':
li = i
flag = True
while arr[li][j] == 'X':
li += 1
if arr[li][j] == 'D':
flag = False
break if flag:
fall[(i, j)] = (li, j)
visited = [[INF] * M for _ in range(N)]
dijkstra(ci, cj)
pass
- 매번 딕셔너리를 찾아보는 것이 아닌 평지와 사다리인 경우 좌우 + 아래, 좌우 + 위 아래를 주어진 배열에서 바로바로 찾도록 하였다.
- 또한, 떨어지는 곳도 배열에 표시해주어 바로바로 이동하도록 해주었다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from heapq import heappush, heappop
INF = float('inf')
def dijkstra(ci, cj):
q = [(0, ci, cj)]
visited[ci][cj] = 0
while q:
val, si, sj = heappop(q)
if arr[si][sj] == 'E':
print(val)
return
if visited[si][sj] < val :
continue
# 평지인 경우 현재 위치에서 내려갈 수 있는 사다리 있는지 체크
# 좌우 체크
if arr[si][sj] == 'F':
for j in [-1, 1]:
ni, nj = si, sj + j
if 0<=nj<M and arr[ni][nj] != 'D':
if visited[ni][nj] > val + 1:
visited[ni][nj] = val + 1
heappush(q, (val+1, ni, nj))
if 0<= si+1 < N and arr[si+1][sj] == 'L':
if visited[si+1][sj] > val+5:
visited[si+1][sj] = val + 5
heappush(q, (val+5, si+1, sj))
# 사다리인 경우
# 올라가는 경우와 내려갈 수 있는 경우, 좌우 체크
elif arr[si][sj] == 'L':
for j in [-1, 1]:
ni, nj = si, sj + j
if 0 <= nj < M and arr[ni][nj] != 'D':
if visited[ni][nj] > val + 1:
visited[ni][nj] = val+1
heappush(q, (val + 1, ni, nj))
if 0<=si+1< N and arr[si+1][sj] == 'L':
if visited[si+1][sj] > val + 5:
visited[si+1][sj] = val+ 5
heappush(q, (val+5, si+1, sj))
if 0<=si-1<N and arr[si-1][sj] != 'D' and arr[si-1][sj] != 'X':
if visited[si-1][sj] > val + 5:
visited[si-1][sj] = val+5
heappush(q, (val+5, si-1, sj))
# 바닥이 없는경우
else:
ni = arr[si][sj][0]
nj = arr[si][sj][1]
if visited[ni][nj] > val + 10:
visited[ni][nj] = val + 10
heappush(q, (val+10, ni, nj))
print('dodo sad')
return
N, M = map(int, input().split())
arr = [list(input().rstrip()) for _ in range(N)]
fall = []
# 순회하며 출발위치와
# 떨어지는 곳이라면 낙하지점을 기록해준다.
for i in range(N):
for j in range(M):
if arr[i][j] == 'C':
ci, cj = i, j
arr[i][j] = 'F'
elif arr[i][j] == 'X':
fall.append((i, j))
li = i
temp = []
while li < N and arr[li][j] == 'X':
temp.append((li, j))
li += 1
if arr[li][j] == 'D':
for ti, tj in temp:
arr[ti][tj] = 'D'
else:
for ti, tj in temp:
arr[ti][tj] = [li, j]
visited = [[INF] * M for _ in range(N)]
dijkstra(ci, cj)
728x90
'ALGORITHM > 다익스트라, 벨만포드, 플로이드워셜' 카테고리의 다른 글
[백준 14619번] 파이썬 - 섬 여행 (0) | 2023.08.14 |
---|---|
[프로그래머스 Lv3] 파이썬 - 등산 코스 정하기 (0) | 2023.07.29 |
[백준 4485번] 파이썬 - 녹색 옷 입은 애가 젤다지? (0) | 2023.04.04 |
[백준 17182번] 파이썬 - 우주 탐사선 (0) | 2023.01.12 |
[백준 14938번] 파이썬 - 서강 그라운드 (0) | 2022.12.29 |