[문제 풀이] 프로그래머스 - Lv3 여행경로

Borahm·2021년 4월 30일
0
post-thumbnail

프로그래머스 - 여행경로

1. 문제

https://programmers.co.kr/learn/courses/30/lessons/43164

2. 고려할 사항

  • 모든 공항은 알파벳 대문자 3글자로 이루어집니다.
  • 주어진 공항 수는 3개 이상 10,000개 이하입니다.
  • tickets의 각 행 [a, b]는 a 공항에서 b 공항으로 가는 항공권이 있다는 의미입니다.
  • 주어진 항공권은 모두 사용해야 합니다.
  • 만일 가능한 경로가 2개 이상일 경우 알파벳 순서가 앞서는 경로를 return 합니다.
  • 모든 도시를 방문할 수 없는 경우는 주어지지 않습니다.
  • 항상 "ICN" 공항에서 출발합니다.

3. 풀이

  • 알파벳 순으로 방문하기 위해 인수를 미리 정렬한다.
  • 그 이후 인수를 인접 리스트 그래프로 만든다.
    - 인수로 주어진 리스트를 그대로 사용할 수도 있다. 이때에는 특정 공항을 찾기 위해 반복문 + 조건문을 사용한다.
    • 나의 경우 이름을 찾는 반복문을 피하기 위해 인접 리스트를 사용하였고,
      출발지 공항의 이름을 키로, 도착지 공항의 이름을 값으로 사용하였다.
  • ICN 부터 DFS 방식으로 인접 리스트의 요소들을 방문한다.
    - DFS는 그래프 상에서 두 정점 사이의 경로가 있는지 확인할 수 있다.
    • 어떤 정점 v에 대해 dfs(v)를 하면, v에서부터 간선을 통해 이동할 수 있는 모든 정점을 방문하게 된다.
    • 특히 모든 간선을 정확히 한 번씩 지나는 경우 dfs를 활용하여 문제를 해결할 수 있다.

4. 어려운 점

  • 이 문제에서 어려운 부분은 정점을 다 돌기 전에 간선이 끊겨 경로가 중간에 종료될 수 있다는 점이다.
  • 해결 방법은 각 간선을 따라가는 순간에 경로를 추가하지 않고, 재귀 호출이 끝나고 반환되기 전 경로를 추가하는 것이다.
  • 따라서 경로의 끝점부터 역순으로 정점이 추가되므로 결과적으로 마지막엔 경로를 한 번 뒤집어주어야 한다.
  • 좀 더 이해를 돕자면, 만약 어떤 정점에서 아직 따라가지 않은 간선이 있을 때, 경로에는 지금까지 찾은 경로의 뒷부분(역순시)만이 저장되어 있다.
  • 이때 새 경로를 찾더라도 경로 중간에 끼워 주지 않는다. 대신 지금까지 만든 부분의 맨 뒤에 새 경로를 붙이고 나머지 부분을 계속 이어붙여준다.

5. 풀이 코드

def make_graph(tickets):
    adjacents = {}
    for from_port, to_port in tickets:
        adjacents[from_port] = adjacents.get(from_port, []) + [to_port]
    return adjacents


def dfs(now, ticket_graph, result):
    if ticket_graph.get(now):
        for i in range(len(ticket_graph[now])):
            while ticket_graph[now]:
                next = ticket_graph[now][i]
                ticket_graph[now].remove(next)
                dfs(next, ticket_graph, result)
    result.append(now)
    return result


def solution(tickets):
    tickets.sort()
    start = "ICN"
    ticket_graph = make_graph(tickets)
    result = dfs(start, ticket_graph, [])
    return result[::-1]


if __name__ == '__main__':
    tickets = [["ICN", "ABC"], ["JFK", "ICN"], ["ICN", "JFK"], ["ABC", "DEF"], ["DEF", "ABC"]]
    print(solution(tickets))

0개의 댓글