깊이/너비 우선 탐색(DFS/BFS) - 여행경로** (Lv.3)

2022. 3. 7. 16:042022/Programmers

문제 설명

주어진 항공권을 모두 이용하여 여행경로를 짜려고 합니다. 항상 "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"]

입출력 예 설명

예제 #1

["ICN", "JFK", "HND", "IAD"] 순으로 방문할 수 있습니다.

 

예제 #2

 

["ICN", "SFO", "ATL", "ICN", "ATL", "SFO"] 순으로 방문할 수도 있지만 ["ICN", "ATL", "ICN", "SFO", "ATL", "SFO"] 가 알파벳 순으로 앞섭니다.

 

<My Source Code 1>

from collections import defaultdict
def solution(tickets):
    answer = []; tempDict = defaultdict(list)
    for i, j in tickets:
        tempDict[i].append(j)
            
    answer = ["ICN"]; depart = "ICN"; arrive = ""
    while bool(tempDict) :
        if len(answer) == 1:
            arrive = min(tempDict[depart])
        else:
            depart = arrive; arrive = min(tempDict[depart])
            
        if len(tempDict[depart]) == 1: del tempDict[depart]
        else: tempDict[depart].remove(arrive)
        
        answer.append(arrive)
    return answer

- 출발지와 도착지를 딕셔너리로 만들고, 동일한 출발지에 대해서는 출발 우선순위대로 정렬한다.

- 첫 출발지는 무조건 "ICN"으로 고정한다.

 

이 두가지 아이디어를 가지고 문제를 풀었다. 

하지만 반은 맞고, 반은 런타임 에러가 났다.

 

 

<My Source Code 2>

from collections import defaultdict
def solution(tickets):
    answer = []
    tempDict = defaultdict(list)
    for i, j in tickets:
        tempDict[i].append(j)
            
    answer = ["ICN"]; depart = "ICN"; arrive = ""
    while bool(tempDict):
        if len(answer) != 1:
            depart = arrive
            
        # min(tempDict[depart]) -> tempDict[depart].pop()
        arrive = tempDict[depart].pop()
        answer.append(arrive)
            
        if len(tempDict[depart]) == 0: del tempDict[depart]

    return answer

여러 부분이 바꼈지만, 50점에서 75점으로 (런타임 에러 2개 -> 런타임 에러 1개) 효율성을 높인건 min으로 먼저 오는 알파벳을 뽑아서 arrive에 할당했던 것을 pop으로 그냥 뒤에 있는 것을 하나 가져오게 바꾼것이였다.

 

조건에서

  • 만일 가능한 경로가 2개 이상일 경우 알파벳 순서가 앞서는 경로를 return 합니다.

이 부분이 있어서 min을 했던건데... 왜 정렬 없이 pop을 했는데 오답이 나지 않는지... 좀 살펴봐야 할 것 같다.

 

근데 여러 사람들의 코드를 참고하다가 내가 간과한 부분이 하나 있다는 것을 알았다.

만약 ['ICN', 'AAA'], ['ICN', 'BBB'], ['BBB', 'ICN']인 경우, AAA로 가는게 조건에 의하면 맞지만 그렇게 하면 나머지 두 나라를 가지 못하게 된다. 

 

이 문제가 속한 부분이 'DFS'/'BFS'인데 난 그렇게 풀지 않은 것이다.

 

from collections import defaultdict
def solution(tickets):
    answer = []
    tempDict = defaultdict(list)
    for i, j in tickets:
        tempDict[i].append(j)
        
    def dfs():
        stack = ["ICN"]
        while stack:
            airport = stack[-1]
            if airport not in tempDict or not tempDict[airport] :
                visited.append(stack.pop())
            else :
                stack.append(tempDict[airport].pop(0))

    visited = list()
    for k in tempDict.keys() :
        tempDict[k].sort()
    dfs()

    return visited[::-1]

위는 다른사람의 풀이를 참고한 것이다.