인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

xk130님의 프로필 이미지

작성한 질문수

세계 대회 진출자가 알려주는 코딩테스트 A to Z (with Python)

그래프 최단 경로 알고리즘 (다익스트라) [개념]

다익스트라 음수 간선

해결된 질문

작성

·

72

0

다익스트라는 음수 간선이 존재하는 경우 사용할 수 없다 라고 하셨는데 다익스트라 개념 강의에 나온 예시 코드의 경우에는 음수 간선이 존재해도 사용할 수 있는거 아닌가요?

 

이미 방문한 노드(최단경로를 확정한 경우)를 다시 방문하지 않는다면 음수 간선이 존재하면 최단 경로를 구할 수 없을것 같은데 강의에 나온 예시 코드는 방문을 했더라도(최단 경로를 확정 했더라도) 다시 heap에서 꺼내어 비교하는 과정이 있으므로 음수 간선이 존재해도 가능할 것 같아 질문드립니다.

답변 1

0

알리 Ally님의 프로필 이미지
알리 Ally
지식공유자

안녕하세요 ,xk130님!

다익스트라 알고리즘에서 의문을 가질만한 점을 잘 짚어주신 것 같습니다.

 

강의의 예시 코드는 다익스트라 코드를 좀 더 간략하게 표현한 것이며, 사실은 아래의 코드와 같이 # 추가된 부분을 적어 주는 것이 정석적인 코드입니다. 아래의 코드에서는 음수 간선이 존재하는 경우에 다익스트라를 쓰지 못하는 이유가 이해가실 거라고 생각합니다.
편의상 강의의 예시 코드를 A, 아래의 정석적인 코드를 B라고 부르겠습니다.

while not pq.empty(): # pq.queue
    cur_dist, cur_node = pq.get()
    
    if cur_dist > dist[cur_node]: # 추가된 부분
        continue

    for adj_node, adj_dist in adj_list[cur_node]:
        temp_dist = cur_dist + adj_dist
        if temp_dist < dist[adj_node]:
            pq.put([temp_dist, adj_node])
            dist[adj_node] = temp_dist

음수 간선이 존재하지 않는 경우에 #추가된 부분을 작성하지 않은 A코드에서도 다익스트라 알고리즘이 잘 돌아갑니다. 이유: 첫 방문이 아닌 경우에 B코드에서는 cur_dist > dist[cur_node]으로 바로 걸러지지만, A코드에서는 아래의 for문을 돌며 인접한 간선을 둘러보는 작업을 하기 때문에 약간의 연산이 더 걸리게 됩니다. (하지만, for문만 수행할 뿐 최단 heap에 경로의 후보를 넣는 일은 발생하지 않습니다.) 즉, A코드는 B코드보다 상수배 정도 비효율적인 알고리즘이라고 생각하시면 됩니다.

 

A코드와 B코드 모두 잘 돌아가며 시간 복잡도에서도 별 차이가 없지만, A코드는 다익스트라 알고리즘을 이해하기에 헷갈림을 유발할 수 있을 거 같아, B코드로 강의 자료를 업데이트하였습니다.

 

 

강의의 예시 코드 A는 음수 간선이 존재할 때 잘 돌아갈까?

이제 강의의 예시 코드 A에서는 음수 간선이 존재하는 경우에 제대로 동작하는지 생각해 봅시다.

결론부터 말씀드리자면, 쓸 수는 있으나 시간 복잡도가 굉장히 크게 나올 수 있습니다. (즉, 이러한 경우에는 벨만-포드나 플로이드-워셜 알고리즘을 쓰는 게 더 나은 것이죠.) 시간 복잡도가 크게 나오는 이유는 다익스트라 알고리즘에서 어떤 노드가 최단 거리로 확정되는 순간은 그 노드가 heap에서 나오는 시점입니다. 하지만, 음수 간선이 존재한다면 이러한 전제가 틀리게 되는데요.

즉, 음수 간선이 존재하는 경우의 A코드(강의의 예시 코드를 의미)는 어떤 노드가 heap에서 나오더라도 그 노드까지의 다른 최단 경로가 존재할 수 있습니다. 이러한 이유 때문에 각 노드의 방문은 최단 거리로써의 방문이 1번이 아닌 여러 번을 할 수 있게 되므로 시간 복잡도가 굉장히 커지게 됩니다.

 


사실, A코드가 B코드에 비해 상수배 느린지에 대한 증명, A코드가 음수 간선이 존재할 때 잘 돌아간다는 타당성, 음수 간선이 존재할 때 A코드의 최악의 시간 복잡도 등에 대해 정확히 짚고 넘어가는 것이 맞지만 답변이 너무 길어질 거 같아 간단하게 답변을 드렸습니다. 위의 내용이 정확히 이해가지 않더라도 정석적인 코드B가 잘 돌아간다는 정도만 이해하고 넘어가셔도 될 것 같습니다!

 

혹시 제가 설명한 부분에 대해서 더 자세히 알고 싶으시다면, 추가 질문 주시면 감사하겠습니다!
더 자세한 동작 과정과 증명에 대한 디테일한 내용을 알려드리겠습니다 :)

xk130님의 프로필 이미지

작성한 질문수

질문하기