Prim과 Dijkstra의 알고리즘의 차이점은 무엇입니까?


95

Dijkstra와 Prim의 알고리즘의 정확한 차이점은 무엇입니까? 나는 Prim이 MST를 줄 것이라는 것을 알고 있지만 Dijkstra가 생성 한 트리도 MST가 될 것입니다. 그렇다면 정확한 차이점은 무엇입니까?


5
Dijkstra입니다. "ij"는 네덜란드어로 diphthong (글라이딩 모음)이며 "j"가 자음이 아닌 곳입니다.

23
어떤 방법 으로든 질문을 받았습니다.
anuj pradhan 2013 년

4
차이점을 구별하는 가장 좋은 방법은 소스 코드DijkstraPrim을 읽는 것 입니다. 주요 차이점은 Prim graph[u][v] < key[v]과 Dijkstra dist[u]+graph[u][v] < dist[v]입니다. 따라서이 두 페이지 의 그래프 에서 볼 수 있듯이 주로이 두 줄의 코드로 인해 서로 다릅니다 .
JW.ZG

답변:


150

Prim의 알고리즘 은 그래프 의 최소 스패닝 트리 를 구성하는데 , 이는 그래프의 모든 노드를 연결하는 트리이며 모든 노드를 연결하는 모든 트리 중에서 총 비용이 가장 적습니다. 그러나 MST에서 두 노드 사이의 경로 길이는 원래 그래프에서 두 노드 사이의 최단 경로가 아닐 수 있습니다. 예를 들어, 그래프의 노드를 물리적으로 연결하여 최소 총 비용으로 노드에 전기를 공급하려는 경우 MST가 유용합니다. 두 노드 사이의 경로 길이가 최적이 아닐 수도 있다는 것은 중요하지 않습니다. 두 노드가 연결되어 있다는 사실 만 염두에두기 때문입니다.

Dijkstra의 알고리즘 은 일부 소스 노드에서 시작 하는 최단 경로 트리를 구성 합니다. 최단 경로 트리는 그래프의 모든 노드를 다시 소스 노드에 연결하는 트리이며 소스 노드에서 그래프의 다른 노드까지의 경로 길이가 최소화된다는 속성이 있습니다. 예를 들어 모든 사람이 주요 랜드 마크에 도달 할 수 있도록 최대한 효율적으로 도로 네트워크를 구축하려는 경우 유용합니다. 그러나 최단 경로 트리는 최소 스패닝 트리가 보장되지 않으며 최단 경로 트리의 가장자리에있는 비용의 합계가 MST 비용보다 훨씬 클 수 있습니다.

또 다른 중요한 차이점은 알고리즘이 작동하는 그래프 유형에 관한 것입니다. Prim의 알고리즘은 MST의 개념이 그래프가 본질적으로 무 방향이라고 가정하기 때문에 무 방향 그래프에서만 작동합니다. (방향성 그래프에 대해 "최소 스패닝 수목"이라는 것이 있지만이를 찾는 알고리즘은 훨씬 더 복잡합니다.) Dijkstra의 알고리즘은 최단 경로 트리가 실제로 방향을 지정할 수 있기 때문에 방향성 그래프에서 잘 작동합니다. 또한 Dijkstra의 알고리즘 은 음의 에지 가중치를 포함하는 그래프에서 반드시 올바른 솔루션을 산출하지는 않지만 Prim의 알고리즘은이를 처리 할 수 ​​있습니다.

도움이 되었기를 바랍니다!


첫 번째 단락은 말이되지 않습니다. 질문은 Dijkstra 와 Prim 의 차이점입니다 . 여기서 Dijkstra 는 당신이 말한 내용에 관한 것이 the length of a path between **any** two nodes아니라, src 노드와 Prim의 다른 노드 사이의 거리가 가장 짧지 않은 경우 왜 가장 짧지 않은지 집중해야합니다. 나는 그가 Primsrc 노드를 다른 노드에 요청해야한다고 생각 합니다 . Prim의 두 노드 에 대해 이야기 한 이유는 무엇 입니까? 물론 가장 짧은 것은 아닙니다.
JW.ZG

2
Dijkstra의 알고리즘에 대한 단락에서 최단 경로 트리가 소스 노드에서 시작되는 최단 경로에 대한 최소화 자일뿐임을 명확히하기 위해 단락의 문구를 정리했습니다. 내가 대답을 구조화 한 이유 는 알고리즘이 왜 다른 결과를 생성하는지, 왜 같을 것이라고 기대하지 않는지 더 높은 수준에서 보여 주기 보다는 알고리즘이 찾은 것을 설명하는 방법 이었습니다.
templatetypedef

1
가장 간단한 설명은 Prims 에서는 시작 노드를 지정하지 않았지만 dijsktra에서는 주어진 노드에서 다른 모든 노드까지의 최단 경로를 찾아야합니다 (시작 노드가 필요함). 참조 stackoverflow.com/a/51605961/6668734
디팍 야다 브

1
@templatetypedef- "그리고 [Dijkstra를 사용하여] 이러한 트리 를 구축 하는 비용은 MST 비용보다 훨씬 클 수 있습니다 ." 자세히 설명해 주시겠습니까?
Amelio Vazquez-Reina

1
@ AmelioVazquez-Reina 죄송합니다, 그 비트는 모호합니다. 내가 의미하는 바는 최단 경로 트리의 가장자리에있는 가중치의 합이 MST의 가장자리에있는 가중치의 합보다 훨씬 클 수 있다는 것입니다.
templatetypedef

84

Dijkstra의 알고리즘은 MST를 생성하지 않고 최단 경로를 찾습니다.

이 그래프를 고려하십시오

       5     5
  s *-----*-----* t
     \         /
       -------
         9

최단 경로는 9이고 MST는 10에서 다른 '경로'입니다.


2
감사합니다 ... 알아 두어야 할 좋은 점을 지우 셨습니다. 지금까지 dijkstra가 생성 한 출력이 MST가 될 것이라고 생각했지만 좋은 예를 들어 의심을 없앴습니다. 'kruskal'을 사용하여 MST를 찾을 수 있는지 명확하게 알 수 있습니다. 그러면 언급 한 것과 동일한 경로를 얻게됩니다. . 감사합니다
anuj pradhan 2013-01-03

8
더 정확하게 The shortest path is 9-... s에서 t로. s에서 시작하는 Dijkstra의 알고리즘에 의해 생성 된 그래프의 가중치는 14 (5 + 9)입니다.
Bernhard Barker

1
@Dukeling-응? Dijkstra의 나무 / 그래프의 무게는 무의미합니다. 그게 요점입니다 ....
dfb

4
매우 간결하게 설명되어 있습니다!
Ram Narasimhan

1
@dfb : 일반적으로 특정 정점 쌍 사이의 최단 경로를 얻기 위해 Dijkstra의 알고리즘 만 실행하지만 실제로 모든 정점을 방문 할 때까지 계속 진행할 수 있습니다. 그러면 templatetypedef의 대답으로 "최단 경로 트리"가 제공됩니다. 설명합니다.
j_random_hacker

65

Prim과 Dijkstra 알고리즘은 "relax function"을 제외하고 거의 동일합니다.

꼼꼼한:

MST-PRIM (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v)    <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

Dijkstra :

Dijkstra (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v) + u.key  <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

유일한 차이점은 릴랙스 기능인 화살표로 표시됩니다.

  • 최소 스패닝 트리를 검색하는 Prim은 모든 정점을 덮는 전체 가장자리의 최소값 만 고려합니다. 릴렉스 기능은alt = w(u,v)
  • 최소 경로 길이를 검색하는 Dijkstra는 에지 누적을 고려합니다. 릴렉스 기능은alt = w(u,v) + u.key

코드 수준에서 다른 차이점은 API입니다. 프림은 방법이 edges()다 익스트라가있는 동안, MST 가장자리를 반환하기를 distanceTo(v), pathTo(v)S는 정점과의 초기화 익스트라이고, 각각의 소스에서 정점 V에 소스에서 정점 V까지의 거리 및 경로를 반환한다.
nethsix

1
추론, 임의의 소스 정점으로 Prim을 초기화하면 s는에 대해 동일한 출력을 반환 edges()하지만 s가 다른 초기화 Dijkstra는 distanceTo(v),에 대해 다른 출력을 반환 pathTo(v)합니다.
nethsix

프림은 음의 무게를 허용합니까? 그렇다면 이것은 또 다른 차이점입니다. 나는 큰 양의 아니오를 추가하여 프림에 음의 가중치를 허용 할 수 있다고 읽었습니다. 모든 가치를 긍정적으로 만듭니다.
Akhil Dad

1
내 혼란을 해결했습니다! 완벽한 답변 !!
Dhananjay Sarsonia 2011

여기서 처리 된 정점은 무 방향 그래프에 대해 무시되어야합니다
Mr AJ

53

Dijsktra의 알고리즘은 노드 i에서 모든 노드까지 의 최소 ​​거리 찾습니다 (i 지정). 따라서 그 대가로 노드 i에서 최소 거리 트리를 얻습니다.

Prims 알고리즘은 주어진 그래프에 대한 최소 스패닝 트리 가져옵니다 . 모든 비용의 합계가 가능한 최소 인 동안 모든 노드를 연결하는 트리입니다.

따라서 Dijkstra 를 사용하면 선택한 노드에서 최소 비용으로 다른 노드로 이동할 수 있습니다. Prim 's에서는이를 얻을 수 없습니다.


가장 간단한 설명은 Prims 에서 시작 노드를 지정하지 않았지만 dijsktra에서는 주어진 노드에서 다른 모든 노드로의 최단 경로를 찾아야합니다 (시작 노드가 필요함). 참조 stackoverflow.com/a/51605961/6668734
디팍 야다 브

32

내가 보는 유일한 차이점은 Prim의 알고리즘은 최소 비용 에지를 저장하는 반면 Dijkstra의 알고리즘은 소스 버텍스에서 현재 버텍스까지의 총 비용을 저장한다는 것입니다.

Dijkstra는 비용이 최소가되도록 소스 노드에서 대상 노드로가는 길을 제공합니다. 그러나 Prim의 알고리즘은 모든 노드가 연결되고 총 비용이 최소가되도록 최소 스패닝 트리를 제공합니다.

간단히 말해서 :

따라서 여러 도시를 연결하기 위해 기차를 배치하려면 Prim의 algo를 사용합니다. 그러나 가능한 한 많은 시간을 절약하면서 한 도시에서 다른 도시로 이동하려면 Dijkstra의 algo를 사용합니다.


24

둘 다 다음과 같이 정확히 동일한 일반 알고리즘을 사용하여 구현할 수 있습니다.

Inputs:
  G: Graph
  s: Starting vertex (any for Prim, source for Dijkstra)
  f: a function that takes vertices u and v, returns a number

Generic(G, s, f)
    Q = Enqueue all V with key = infinity, parent = null
    s.key = 0
    While Q is not empty
        u = dequeue Q
        For each v in adj(u)
            if v is in Q and v.key > f(u,v)
                v.key = f(u,v)
                v.parent = u

Prim의 경우 통과 f = w(u, v)하고 Dijkstra의 경우 통과 f = u.key + w(u, v)합니다.

또 다른 흥미로운 점은 위의 Generic도 BFS (Breadth First Search)를 구현할 수 있다는 것입니다. 값 비싼 우선 순위 대기열이 실제로 필요하지 않기 때문에 과도 할 수 있습니다. 일반 알고리즘을 BFS로 전환하려면 f = u.key + 1모든 가중치를 1로 적용하는 것과 동일한 방식을 전달합니다 (즉, BFS는 지점 A에서 B로 이동하는 데 필요한 최소 가장자리 수를 제공합니다).

직관

위의 일반적인 알고리즘에 대해 생각하는 좋은 방법은 다음과 같습니다. 두 개의 버킷 A와 B로 시작합니다. 처음에는 버킷 A가 비어 있도록 모든 정점을 B에 넣습니다. 그런 다음 하나의 정점을 B에서 A로 이동합니다. 이제 A의 정점에서 B의 정점까지 교차하는 모든 가장자리를 살펴 봅니다. 이러한 교차 가장자리의 일부 기준을 사용하여 하나의 가장자리를 선택하고 해당 정점을 B에서 A. B가 비워 질 때까지이 과정을 반복합니다.

이 아이디어를 구현하는 무차별 대입 방법은 B로 넘어가는 A의 정점에 대한 가장자리의 우선 순위 대기열을 유지하는 것입니다. 그래프가 희박하지 않으면 문제가 될 것입니다. 그래서 질문은 대신 정점의 우선 순위 대기열을 유지할 수 있습니까? 실제로 이것은 우리의 결정에 따라 B에서 선택할 정점입니다.

역사적 맥락

두 알고리즘이면의 기술의 일반 버전이 개념적으로 전자 컴퓨터가 없었을 때도 1930 년만큼 오래되었다는 것은 흥미 롭습니다.

이야기는 최소 비용의 전기선으로 Moravia (현재 체코 공화국)의 도시를 연결하는 방법을 알아 내려는 가족 친구를위한 알고리즘이 필요한 Otakar Borůvka로 시작됩니다. 그는 컴퓨터 과학이 존재하지 않았기 때문에 1926 년에 수학 관련 저널에 자신의 알고리즘을 발표했습니다. 이것은 Borůvka 알고리즘의 개선을 생각하고 1930 년에 발표 한 Vojtěch Jarník의 관심을 끌었습니다. 그는 실제로 우리가 지금 알고있는 것과 동일한 알고리즘을 발견하여 1957 년에 다시 발견 한 Prim의 알고리즘을 발견했습니다.

이 모든 것들과는 별개로, 1956 년 Dijkstra는 그의 연구소가 개발 한 새로운 컴퓨터의 기능을 보여주는 프로그램을 작성해야했습니다. 그는 컴퓨터가 네덜란드의 두 도시 사이를 여행 할 연결을 찾는 것이 멋질 것이라고 생각했습니다. 그는 20 분 만에 알고리즘을 설계했습니다. 그는 (그의 컴퓨터가 6 비트이기 때문에) 약간 단순화 된 64 개 도시의 그래프를 만들고이 1956 년 컴퓨터 용 코드를 작성했습니다. 그러나 그는 주로 컴퓨터 과학 저널이 없었고 이것이 그다지 중요하지 않을 것이라고 생각했기 때문에 알고리즘을 발표하지 않았습니다. 다음 해에 그는 전선 길이를 최소화하기 위해 새 컴퓨터의 터미널을 연결하는 문제에 대해 배웠습니다. 그는이 문제에 대해 생각하고 Jarník / Prim '을 재발견했습니다. 그가 1 년 전에 발견 한 최단 경로 알고리즘과 동일한 기술을 다시 사용하는 s 알고리즘. 그그의 알고리즘은 모두 펜이나 종이를 사용하지 않고 설계되었다고 언급 했습니다. 1959 년에 그는 2 페이지 반에 불과한 논문에 두 알고리즘을 모두 발표했습니다 .


감사! 출구가 모호합니다. 아무 일도 일어나지 않아도 루프를 빠져 나가는 이유는 무엇입니까?
amirouche

15

Dijkstra는 시작 노드와 다른 모든 노드 사이의 최단 경로를 찾습니다. 따라서 그 대가로 시작 노드에서 최소 거리 트리를 얻습니다. 즉, 가능한 한 효율적으로 다른 모든 노드에 도달 할 수 있습니다.

Prims 알고리즘은 주어진 그래프, 즉 모든 비용의 합계가 가능한 최소값 인 동안 모든 노드를 연결하는 트리에 대한 MST를 얻습니다.

현실적인 예를 들어 짧은 이야기를 만들려면 :

  1. Dijkstra는 이동 시간과 연료를 절약하여 각 목적지까지의 최단 경로를 알고 싶어합니다.
  2. Prim은 기차 레일 시스템을 효율적으로 배치하는 방법, 즉 자재 비용을 절약하는 방법을 알고 싶어합니다.

10

Dijkstra의 Algorithm의 위키피디아 기사 에서 직접 :

Dijkstra의 알고리즘의 기초가되는 프로세스는 Prim의 알고리즘에서 사용되는 탐욕스러운 프로세스와 유사합니다. Prim의 목적은 그래프의 모든 노드를 연결하는 최소 스패닝 트리를 찾는 것입니다. Dijkstra는 두 개의 노드에만 관련됩니다. Prim 's는 시작 노드에서 경로의 총 가중치를 평가하지 않고 개별 경로 만 평가합니다.


5
"Dijkstra는 두 개의 노드에만 관심이 있습니다."
tmyklebu

5

최근에 같은 질문으로 귀찮아서 이해를 공유 할 수있을 것 같습니다 ...

이 두 알고리즘 (Dijkstra 및 Prim)의 주요 차이점은 해결하도록 설계된 문제, 즉 두 노드 사이의 최단 경로와 MST (Minimum Spanning Tree)의 근원이라고 생각합니다. 공식은 노드 st 사이의 최단 경로를 찾는 것이며, 합리적인 요구 사항은 그래프의 각 가장자리를 최대 한 번 방문하는 것입니다. 그러나 모든 노드를 방문 할 필요 는 없습니다 . 후자 (MST)는 모든 노드 (최대 한 번)를 방문하도록하고 각 에지를 최대 한 번 방문하는 동일한 합리적 요구 사항을 적용하는 것입니다.

즉, Dijkstra는 결과에 대해 걱정하지 않고 s 에서 t으로 이동할 수있는 "바로 가기"를 허용합니다. 일단 t에 도달하면 끝났습니다! MST 에도 s 에서 t 까지 경로가 있지만이 s - t 경로는 모든 나머지 노드를 고려하여 생성 되므로이 경로는 Dijstra의 알고리즘에서 찾은 s - t 경로 보다 길 수 있습니다 . 다음은 3 개의 노드가있는 빠른 예입니다.

                                  2       2  
                          (s) o ----- o ----- o (t)     
                              |               |
                              -----------------
                                      3

각 상단 가장자리의 비용이 2이고 하단 가장자리의 비용이 3이라고 가정 해 봅시다. 그러면 Dijktra는 중간 노드에 대해 신경 쓰지 않기 때문에 하단 경로를 선택하라고 알려줍니다. 반면에 Prim은 상단 2 개의 가장자리가있는 MST를 반환하여 하단 가장자리를 버립니다.

이러한 차이는 구현의 미묘한 차이에서도 반영됩니다. Dijkstra의 알고리즘에서는 새 노드를 흡수 한 후 s 의 최단 경로를 업데이트하기 위해 모든 노드에 대한 장부 유지 단계가 필요 하지만 Prim의 알고리즘에서는 그런 필요가 없습니다.


3

기본 알고리즘의 주요 차이점은 서로 다른 가장자리 선택 기준에 있습니다. 일반적으로 둘 다 다음 노드를 선택하는 데 우선 순위 대기열을 사용하지만 현재 처리 노드의 인접 노드를 선택하는 기준이 다릅니다. Prim의 알고리즘은 다음 인접 노드도 대기열에 보관해야하는 반면 Dijkstra의 알고리즘은 다음을 수행하지 않습니다.

def dijkstra(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            ...

def prim(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            if v in q and weight(u, v) < v.distance:// <-------selection--------
            ...

vertex.distance 의 계산은 두 번째로 다른 점입니다.


3

Dijkstra의 알고리즘은 노드 i와 j 사이의 단일 소스 최단 경로 문제이지만 Prim의 알고리즘은 최소 스패닝 트리 문제입니다. 이 알고리즘은 '욕심 많은 알고리즘'이라는 프로그래밍 개념을 사용합니다.

이 개념을 확인하면 다음을 방문하십시오.

  1. Greedy 알고리즘 강의 노트 : http://jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf
  2. 최소 스패닝 트리 : http://jeffe.cs.illinois.edu/teaching/algorithms/notes/20-mst.pdf
  3. 단일 소스 최단 경로 : http://jeffe.cs.illinois.edu/teaching/algorithms/notes/21-sssp.pdf

2

Dijkstras 알고리즘 은 최단 경로를 찾는 데만 사용됩니다.

에서 최소 스패닝 트리 (프림의 또는 크루스 칼의 알고리즘) 당신은 최소 에지 값을 최소 egdes를 얻을.

예를 들어 : -하는 것은 당신이 와이어의 이러한 계산을 사용하여 수행 할 수있는 u는 전선의 큰 숫자를 필요로한다 거대한 네트워크를 만들 wan't 경우 상황을 고려해 최소 스패닝 트리 (프림의 또는 크루스 칼의 알고리즘)을 (그것은 것, 즉 최소한의 비용으로 거대한 유선 네트워크 연결을 만들기 위해 최소한의 와이어 수를 제공합니다).

반면 "Dijkstras 알고리즘" 은 노드를 서로 연결하면서 두 노드 사이의 최단 경로를 얻는 데 사용됩니다.


2

가장 간단한 설명은 Prims에서는 시작 노드를 지정하지 않았지만 dijsktra에서는 주어진 노드에서 다른 모든 노드로의 최단 경로를 찾아야합니다 (시작 노드가 필요함).


0

@templatetypedef는 MST와 최단 경로의 차이점을 다루었습니다. 나는 하나 이상의 매개 변수를 입력으로 사용하는 동일한 일반 알고리즘을 사용하여 둘 다 구현할 수 있음을 보여줌으로써 다른 So 답변 에서 알고리즘 차이를 다루었습니다 f(u,v). Prim과 Dijkstra의 알고리즘의 차이점은 단순히 f(u,v)사용 하는 것입니다.


0

코드 수준에서 다른 차이점은 API입니다.

소스 정점 s , 즉 Prim.new(s); S는 모든 정점이 될 수 있으며, 관계없이 S 최소 스패닝 트리 (MST)의 에지가 최종 결과는 동일하다. MST 에지를 얻기 위해 메서드를 호출합니다 edges().

소스 정점으로 Dijkstra를 초기화합니다. s로 . 즉, Dijkstra.new(s)다른 모든 정점에 대한 최단 경로 / 거리를 얻고 자합니다. 최종 결과는 s 에서 다른 모든 정점 까지 최단 경로 / 거리입니다 . 온 따라 다릅니다 . s 에서 정점 v 까지 최단 경로 / 거리를 얻기 위해 각각 distanceTo(v)및 메소드를 호출합니다 pathTo(v).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.