제가 만든 추가 테스트 케이스를 공유합니다.

from collections import deque
import heapq as hq
def solution(n, start, end, roads, traps):
answer = 0
roadsFrom = {}
roadsTo = {}
visited = {}
for i in range(n+1):
visited[i] = {}
roadsFrom[i] = []
roadsTo[i] = []
for s, e, c in roads:
roadsFrom[s].append((e, c))
roadsTo[e].append((s, c))
q = []
hq.heappush(q, [0, start, []])
visited[start][()] = 0
def renewTraps(cur_traps_on, new):
if new not in traps:
return cur_traps_on
if new in cur_traps_on:
cur_traps_on.remove(new)
return cur_traps_on
if new in traps:
cur_traps_on.append(new)
return sorted(cur_traps_on)
return cur_traps_on
def push():
new_traps_on = renewTraps(traps_on.copy(), destination)
if tuple(new_traps_on) in visited[destination] and visited[destination][tuple(new_traps_on)] < count + cost:
return
visited[destination][tuple(new_traps_on)] = count + cost
hq.heappush(q, [count+cost, destination, new_traps_on])
while q:
count, cur, traps_on = hq.heappop(q)
if cur == end:
return count
if cur not in traps_on:
for destination, cost in roadsFrom[cur]:
if destination not in traps_on:
push()
for destination, cost in roadsTo[cur]:
if destination in traps_on:
push()
else:
for destination, cost in roadsFrom[cur]:
if destination in traps_on:
push()
for destination, cost in roadsTo[cur]:
if destination not in traps_on:
push()
return answer
a → b)이 존재할 때, 해당 길을 이용할 수 있는 지를 확인하기 위해서는 a와 b의 활성화 상태만을 확인하면 됩니다. q)에는 현재 방번호와 현재 활성화된 trap들의 번호, 현재 시간이 저장됩니다. (현재 시간을 기준으로 우선순위 큐를 이용하고 있기 때문에 현재 시간이 첫번째 원소로 저장됩니다.)visited 에 저장됩니다.visited[방번호][트랩리스트(frozenset)] 에 해당 방번호에 특정 트랩리스트를 가지고 방문한 최소 cost를 저장하도록 했습니다.visited와 visited[방번호]는 모두 딕셔너리입니다. answer = 0
roadsFrom = {}
roadsTo = {}
visited = {}
for i in range(n+1):
visited[i] = {}
roadsFrom[i] = []
roadsTo[i] = []
for s, e, c in roads:
roadsFrom[s].append((e, c))
roadsTo[e].append((s, c))
처음 세팅 부분입니다.
roadsFrom[i] 는 i번 방에서 출발하는 길들의 (도착 방, 걸리는 시간) 리스트입니다.
roadsTo[i] 는 i번 방으로 도착하는 길들의 (출발 방, 걸리는 시간) 리스트입니다.
while q:
count, cur, traps_on = hq.heappop(q)
if cur == end:
return count
if cur not in traps_on:
for destination, cost in roadsFrom[cur]:
if destination not in traps_on:
push()
for destination, cost in roadsTo[cur]:
if destination in traps_on:
push()
else:
for destination, cost in roadsFrom[cur]:
if destination in traps_on:
push()
for destination, cost in roadsTo[cur]:
if destination not in traps_on:
push()
q에는 count(현재 시간), cur(현재 방번호), traps_on(현재 활성화된 트랩)이 저장됩니다.
현재 방번호가 목적지인 경우에는 값을 리턴하고 종료합니다.
현재 방에서 갈 수 있는 다음 방들을 구하기 위해서는
경우를 나눠 현재 방이 활성화되었는지 확인하고, 활성화되지 않았다면
roadsFrom[cur])에서 목적지도 활성화되지 않은 방들을 찾아 q에 넣으려고 시도합니다(push, 뒷부분에 설명)roadsTo[cur])에서 목적지가 활성화된 방들을 찾아 q에 넣으려고 시도합니다(push)현재 방이 활성화된 경우도 같은 방법으로 q에 넣으려고 시도합니다.
def renewTraps(cur_traps_on, new):
if new not in traps:
return cur_traps_on
if new in cur_traps_on:
cur_traps_on.remove(new)
return cur_traps_on
if new in traps:
cur_traps_on.append(new)
return sorted(cur_traps_on)
return cur_traps_on
def push():
new_traps_on = renewTraps(traps_on.copy(), destination)
if tuple(new_traps_on) in visited[destination] and visited[destination][tuple(new_traps_on)] < count + cost:
return
visited[destination][tuple(new_traps_on)] = count + cost
hq.heappush(q, [count+cost, destination, new_traps_on])
renewTraps 은 현재 활성화된 함정들(cur_traps_on)이 존재하고 새로운 방(new)을 방문하였을 때 새롭게 변경된, 활성화된 함정 리스트를 리턴합니다.
push 는 새로운 목적지를 추가하려고 시도하는 함수입니다. 만약 visited[목적지][트랩] 가 존재하면 해당 목적지에 같은 (활성화된) 트랩 리스트를 가지고 방문한 적이 있다는 뜻입니다. 당시의 비용을 확인하고 비용이 더 적을 때에만 q에 추가합니다. visited[목적지][트랩]가 존재하지 않는다면 해당 목적지에 같은 트랩리스트를 가지고 방문한 적이 없다는 의미이므로 바로 q에 추가합니다.
단순히 deque를 이용하여 BFS를 구현하면 테스트3,4 유형의 테스트를 통과할 수 없습니다.
