Category | ps/bfs & dfs |
---|---|
Tag | bfs & dfs |
Tags | |
난이도 | level 3 |
메모 | |
발행 여부 | |
사이트 | 프로그래머스 |
이해 | 완벽히 이해 |
최종 편집 일시 | |
푼 날짜 |
문제 해설 및 주의사항
원문
문제 설명
주어진 항공권을 모두 이용하여 여행경로를 짜려고 합니다. 항상 "ICN" 공항에서 출발합니다.
항공권 정보가 담긴 2차원 배열 tickets가 매개변수로 주어질 때, 방문하는 공항 경로를 배열에 담아 return 하도록 solution 함수를 작성해주세요.
제한사항
- 모든 공항은 알파벳 대문자 3글자로 이루어집니다.
- 주어진 공항 수는 3개 이상 10,000개 이하입니다.
- tickets의 각 행 [a, b]는 a 공항에서 b 공항으로 가는 항공권이 있다는 의미입니다.
- 주어진 항공권은 모두 사용해야 합니다.
- 만일 가능한 경로가 2개 이상일 경우 알파벳 순서가 앞서는 경로를 return 합니다.
- 모든 도시를 방문할 수 없는 경우는 주어지지 않습니다.
입출력 예
tickets | return |
---|---|
[["ICN", "JFK"], ["HND", "IAD"], ["JFK", "HND"]] | ["ICN", "JFK", "HND", "IAD"] |
[["ICN", "SFO"], ["ICN", "ATL"], ["SFO", "ATL"], ["ATL", "ICN"], ["ATL","SFO"]] | ["ICN", "ATL", "ICN", "SFO", "ATL", "SFO"] |
주의사항
풀이
tickets | return |
---|---|
[["ICN", "JFK"], ["HND", "IAD"], ["JFK", "HND"]] | ["ICN", "JFK", "HND", "IAD"] |
[["ICN", "SFO"], ["ICN", "ATL"], ["SFO", "ATL"], ["ATL", "ICN"], ["ATL","SFO"]] | ["ICN", "ATL", "ICN", "SFO", "ATL", "SFO"] |
- ICN
- SFO ATL
내 풀이 코드 (bfs) 예외 처리 전
import collections
def solution(tickets):
answer = []
graph = collections.defaultdict(list)
for ticket in sorted(tickets, key= lambda x : (x[0], x[1]), reverse=True):
graph[ticket[0]].append(ticket[1])
Q = collections.deque()
Q.append("ICN")
while Q:
current_node = Q.popleft()
answer.append(current_node)
if graph[current_node]:
Q.append(graph[current_node].pop())
return answer
내 풀이 코드 (dfs)
import collections
def solution(tickets):
answer = []
N = 0
graph = collections.defaultdict(list)
for ticket in sorted(tickets, key= lambda x : (x[0], x[1]), reverse=True):
graph[ticket[0]].append(ticket[1])
N += 1
def dfs(current_node, path):
# ticket 의 개수와 맞으면 정답 처리
if len(path) == N + 1:
return path
# ticket 의 개수와 맞지 않으면서 다음 ticket 이 없다면
if len(path) != N + 1 and len(graph[current_node]) == 0:
return -1
for _ in range(len(graph[current_node])):
next_node = graph[current_node].pop() # 맨 끝 추출
ret = dfs(next_node, path + [next_node])
graph[current_node].insert(0, next_node) # 맨 앞에 복구(순서를 바꿔주기 위해서)
if ret and ret != -1: # ret 이 존재하고, path 가 정상적으로 return 됐다면
return ret
answer = dfs("ICN", ["ICN"])
return answer
- 일반적인 dfs 구현은 수월했다.
- 인접 노드를 깊이 우선으로 탐색한다.
- 일반적인 dfs 와 달랐던 점은, 처음에 graph 를 사전 내림차순으로 정렬했기 때문에,
pop
을 활용하여 맨 뒤의 인접 노드부터 순회했다는 점이다. (그래야만이, 사전순으로 오름차순으로 순회가 가능하다.)
- 맨 끝에서
pop
을 했기 때문에, 해당 인접 노드가 정답이 아니라면, 다시insert
해주는 부분이 있다.- 맨 끝에 다시 insert 하지 않고 0번째 index 로 넣어서 사전순은 유지하되 순서는 바꾼다.
# ticket 의 개수와 맞지 않으면서 다음 ticket 이 없다면 if len(path) != N + 1 and len(graph[current_node]) == 0: return -1
- 해당 코드를 잘 보자. 예외 처리. 즉, 히든 케이스를 잘 처리해야 하는 이유를 알 수 있다.
- 인접 노드를 깊이 우선으로 탐색한다.
풀이 코드
from collections import defaultdict
def solution(tickets):
# 특정 티켓의 인접 리스트를 구하는 함수
def init_graph():
routes = defaultdict(list)
for key, value in tickets:
routes[key].append(value)
return routes
# 재귀 호출을 사용한 DFS
def dfs(key, footprint):
if len(footprint) == N + 1:
return footprint
for idx, country in enumerate(routes[key]):
routes[key].pop(idx)
fp = footprint[:] # deepcopy
fp.append(country)
ret = dfs(country, fp)
if ret: return ret # 모든 티켓을 사용해 통과한 경우
routes[key].insert(idx, country) # 통과 못했으면 티켓 반환
routes = init_graph()
for r in routes:
routes[r].sort()
N = len(tickets)
answer = dfs("ICN", ["ICN"])
return answer
퇴고
반응형
'ps > bfs & dfs' 카테고리의 다른 글
[boj.kr] 최단경로 (0) | 2022.02.04 |
---|---|
[프로그래머스] 가장 먼 노드 (1) | 2021.12.20 |
[프로그래머스] 순위 (0) | 2021.12.20 |
[boj.kr] 10026. 적록색약 (0) | 2021.12.20 |
77. Combinations (0) | 2021.12.12 |