Differenza tra gli algoritmi di Prim e Dijkstra?


91

Qual è l'esatta differenza tra gli algoritmi di Dijkstra e Prim? So che Prim's darà un MST ma anche l'albero generato da Dijkstra sarà un MST. Allora qual è la differenza esatta?


3
È Dijkstra. "ij" è un dittongo (vocale scorrevole) in olandese, ed è l'unico posto dove "j" non è una consonante.

22
in qualsiasi modo hai ottenuto la domanda.
anuj pradhan

4
Il modo migliore per distinguere la loro differenza è leggere un po 'di codice sorgente , Dijkstra e Prim . La differenza principale è qui: per Prim graph[u][v] < key[v]e per Dijkstra dist[u]+graph[u][v] < dist[v]. Quindi, come puoi vedere dai grafici in quelle due pagine, sono diversi principalmente a causa di queste due righe di codice.
JW.ZG

Risposte:


146

L'algoritmo di Prim costruisce uno spanning tree minimo per il grafo, che è un albero che collega tutti i nodi nel grafo e ha il minor costo totale tra tutti gli alberi che connettono tutti i nodi. Tuttavia, la lunghezza di un percorso tra due nodi qualsiasi nell'MST potrebbe non essere il percorso più breve tra questi due nodi nel grafico originale. Gli MST sono utili, ad esempio, se si desidera collegare fisicamente i nodi nel grafico per fornire loro elettricità al minor costo totale. Non importa che la lunghezza del percorso tra due nodi potrebbe non essere ottimale, poiché tutto ciò che ti interessa è il fatto che siano collegati.

L'algoritmo di Dijkstra costruisce un albero dei cammini minimi partendo da un nodo sorgente. Un albero del percorso più breve è un albero che collega tutti i nodi nel grafico al nodo di origine e ha la proprietà che la lunghezza di qualsiasi percorso dal nodo di origine a qualsiasi altro nodo nel grafico è ridotta al minimo. Ciò è utile, ad esempio, se si desidera costruire una rete stradale che rendesse il più efficiente possibile per tutti raggiungere un punto di riferimento importante. Tuttavia, non è garantito che l'albero del percorso più breve sia uno spanning tree minimo e la somma dei costi sui bordi di un albero del percorso più breve può essere molto maggiore del costo di un MST.

Un'altra importante differenza riguarda i tipi di grafici su cui lavorano gli algoritmi. L'algoritmo di Prim funziona solo su grafici non orientati, poiché il concetto di MST presuppone che i grafici siano intrinsecamente non orientati. (C'è qualcosa chiamato "arborescenza di copertura minima" per i grafi diretti, ma gli algoritmi per trovarli sono molto più complicati). L'algoritmo di Dijkstra funzionerà bene sui grafi diretti, poiché gli alberi dei percorsi più brevi possono effettivamente essere diretti. Inoltre, l'algoritmo di Dijkstra non fornisce necessariamente la soluzione corretta nei grafici contenenti pesi degli archi negativi , mentre l'algoritmo di Prim può gestirlo.

Spero che questo ti aiuti!


Il primo paragrafo non ha senso, amico. La domanda è qual è la differenza tra Dijkstra e Prim, dove Dijkstra non riguarda ciò che hai detto the length of a path between **any** two nodes, dovresti solo concentrarti sul perché la distanza tra il nodo src e qualsiasi altro nodo in Prim non è più breve se non è più breve. Penso che stia chiedendo il nodo src in Prim a qualsiasi altro nodo . Perché hai parlato di due nodi qualsiasi in Prim? Ovviamente non è il più breve.
JW.ZG

1
Ho ripulito la dicitura nel paragrafo sull'algoritmo di Dijkstra per chiarire che l'albero dei percorsi più brevi è solo un minimizzatore per i percorsi più brevi che hanno origine nel nodo di origine. Il motivo per cui ho strutturato la mia risposta in questo modo è stato un modo per illustrare ciò che trovano gli algoritmi piuttosto che come funzionano per mostrare a un livello superiore perché producono risultati diversi e perché non ti aspetteresti che fossero gli stessi.
templatetypedef

1
La spiegazione più semplice è che in Prims non si specifica il nodo iniziale , ma in dijsktra (è necessario disporre di un nodo iniziale) è necessario trovare il percorso più breve dal nodo dato a tutti gli altri nodi. Vedi stackoverflow.com/a/51605961/6668734
Deepak Yadav

1
@templatetypedef - Quando dici: "e il costo della costruzione di un albero del genere [con Dijkstra] potrebbe essere molto più grande del costo di un MST." puoi elaborare per favore?
Amelio Vazquez-Reina

1
@ AmelioVazquez-Reina Scusa, quel bit è ambiguo. Quello che volevo dire è che la somma dei pesi sui bordi di un albero dei percorsi più brevi può essere molto più grande della somma dei pesi sui bordi in un MST.
templatetypedef

82

L'algoritmo di Dijkstra non crea un MST, trova il percorso più breve.

Considera questo grafico

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

Il percorso più breve è 9, mentre l'MST è un "percorso" diverso a 10.


2
Ok grazie ... hai cancellato un buon punto da notare. Fino ad ora stavo considerando che l'output generato da dijkstra sarà un MST ma hai chiarito il dubbio con un buon esempio. Posso vedere chiaramente se troverò un MST usando diciamo 'kruskal', allora otterrò lo stesso percorso che hai menzionato . Grazie mille
anuj pradhan

8
Più correttamente - The shortest path is 9... da sa t. Il peso del grafico generato dall'algoritmo di Dijkstra, a partire da s, è 14 (5 + 9).
Bernhard Barker

1
@Dukeling - Eh? il peso dell'albero / grafico in Dijkstra non ha senso, questo è il punto ...
dfb

4
Illustrato in modo molto succinto!
Ram Narasimhan

1
@dfb: Normalmente eseguiamo l'algoritmo di Dijkstra solo per ottenere il percorso più breve tra una specifica coppia di vertici, ma in realtà puoi andare avanti finché tutti i vertici non sono stati visitati, e questo ti darà un "albero dei percorsi più brevi", come risposta di templatetypedef spiega.
j_random_hacker

63

Gli algoritmi di Prim e Dijkstra sono quasi gli stessi, ad eccezione della "funzione relax".

Prim:

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
}

L'unica differenza è evidenziata dalla freccia, che è la funzione relax.

  • Il Prim, che cerca l'albero di copertura minimo, si preoccupa solo del minimo dei bordi totali che coprono tutti i vertici. La funzione relax èalt = w(u,v)
  • Il Dijkstra, che cerca la lunghezza minima del percorso, quindi si preoccupa dell'accumulo di bordi. La funzione relax èalt = w(u,v) + u.key

A livello di codice, l'altra differenza è l'API. Prim ha metodo edges()per restituire bordi MST, mentre Dijkstra ha distanceTo(v), pathTo(v)che restituisce rispettivamente distanza dalla sorgente al vertice v, e percorso dalla sorgente al vertice v, dove s è il vertice tua inizializzazione Dijkstra con.
nethsix

1
Corollario, inizializzazione vertice Prim con qualsiasi qualsiasi fonte, s restituisce la stessa uscita per edges(), ma inizializzazione Dijkstra con differenti s tornerà produzione diversa per distanceTo(v), pathTo(v).
nethsix

I prim consentono un peso negativo? se sì, allora questa è un'altra differenza. Ho letto che puoi consentire pesi negativi sui prim aggiungendo un grande no positivo. a ogni valore, rendendolo tutto positivo.
Akhil Dad,

1
Risolto la mia confusione! Risposta perfetta !!
Dhananjay Sarsonia

qui il vertice elaborato deve essere ignorato per il grafico non orientato
Sig. AJ

53

L'algoritmo di Dijsktra trova la distanza minima dal nodo i a tutti i nodi (tu specifichi i). Quindi in cambio ottieni l'albero della distanza minima dal nodo i.

L'algoritmo Prims ti fornisce l'albero di estensione minimo per un dato grafico . Un albero che collega tutti i nodi mentre la somma di tutti i costi è il minimo possibile.

Quindi con Dijkstra puoi passare dal nodo selezionato a qualsiasi altro con il minimo costo , non lo ottieni con Prim's


La spiegazione più semplice è che in Prims non si specifica il nodo iniziale , ma in dijsktra (è necessario disporre di un nodo iniziale) è necessario trovare il percorso più breve dal nodo dato a tutti gli altri nodi. Vedi stackoverflow.com/a/51605961/6668734
Deepak Yadav

32

L'unica differenza che vedo è che l'algoritmo di Prim memorizza un margine di costo minimo mentre l'algoritmo di Dijkstra memorizza il costo totale da un vertice sorgente al vertice corrente.

Dijkstra ti dà un modo dal nodo di origine al nodo di destinazione in modo tale che il costo sia minimo. Tuttavia, l'algoritmo di Prim ti offre uno spanning tree minimo in modo tale che tutti i nodi siano collegati e il costo totale sia minimo.

In parole semplici:

Quindi, se vuoi schierare un treno per connettere diverse città, dovresti usare l'algo di Prim. Ma se vuoi andare da una città all'altra risparmiando più tempo possibile, useresti l'algo di Dijkstra.


24

Entrambi possono essere implementati utilizzando esattamente lo stesso algoritmo generico come segue:

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

Per Prim, pass f = w(u, v)e per Dijkstra pass f = u.key + w(u, v).

Un'altra cosa interessante è che sopra Generic può anche implementare Breadth First Search (BFS) anche se sarebbe eccessivo perché la costosa coda di priorità non è realmente richiesta. Per trasformare l'algoritmo generico in BFS, passare f = u.key + 1che equivale a imporre tutti i pesi a 1 (cioè BFS fornisce il numero minimo di bordi necessari per attraversare dal punto A a B).

Intuizione

Ecco un buon modo per pensare all'algoritmo generico di cui sopra: iniziamo con due bucket A e B. Inizialmente, mettete tutti i vertici in B in modo che il bucket A sia vuoto. Quindi spostiamo un vertice da B ad A. Ora guarda tutti i bordi dai vertici in A che attraversano i vertici in B. Abbiamo scelto un bordo usando alcuni criteri da questi bordi incrociati e spostiamo il vertice corrispondente da B a A. Ripeti questo processo fino a quando B è vuoto.

Un modo brute force per implementare questa idea sarebbe quello di mantenere una coda di priorità dei bordi per i vertici in A che attraversa fino a B. Ovviamente ciò sarebbe problematico se il grafico non fosse sparso. Quindi la domanda sarebbe: possiamo invece mantenere la coda di priorità dei vertici? Questo in effetti possiamo come la nostra decisione alla fine è quale vertice scegliere da B.

Contesto storico

È interessante notare che la versione generica della tecnica alla base di entrambi gli algoritmi è concettualmente vecchia del 1930 anche quando i computer elettronici non erano in circolazione.

La storia inizia con Otakar Borůvka che aveva bisogno di un algoritmo per un amico di famiglia che cercava di capire come collegare le città nel paese della Moravia (ora parte della Repubblica Ceca) con linee elettriche a costo minimo. Pubblicò il suo algoritmo nel 1926 in una rivista di matematica, poiché allora l'informatica non esisteva. Questo portò all'attenzione di Vojtěch Jarník che pensò a un miglioramento dell'algoritmo di Borůvka e lo pubblicò nel 1930. Scoprì infatti lo stesso algoritmo che ora conosciamo come algoritmo di Prim che lo riscoprì nel 1957.

Indipendentemente da tutto ciò, nel 1956 Dijkstra aveva bisogno di scrivere un programma per dimostrare le capacità di un nuovo computer sviluppato dal suo istituto. Ha pensato che sarebbe stato bello avere un computer per trovare i collegamenti per viaggiare tra due città dei Paesi Bassi. Ha progettato l'algoritmo in 20 minuti. Ha creato un grafico di 64 città con alcune semplificazioni (perché il suo computer era a 6 bit) e ha scritto il codice per questo computer del 1956. Tuttavia non ha pubblicato il suo algoritmo perché principalmente non c'erano riviste di informatica e pensava che questo potesse non essere molto importante. L'anno successivo venne a conoscenza del problema del collegamento di terminali di nuovi computer in modo tale da ridurre al minimo la lunghezza dei fili. Ha pensato a questo problema e ha riscoperto Jarník / Prim ' s algoritmo che utilizza ancora la stessa tecnica dell'algoritmo del percorso più breve che aveva scoperto un anno prima. Luiha detto che entrambi i suoi algoritmi sono stati progettati senza utilizzare carta o penna. Nel 1959 pubblicò entrambi gli algoritmi in un articolo di sole 2 pagine e mezzo.


Grazie! L'uscita è nebulosa, perché esce dal loop anche se non accade nulla?
amirouche

15

Dijkstra trova il percorso più breve tra il suo nodo iniziale e ogni altro nodo. Quindi in cambio ottieni la distanza minima dell'albero dal nodo iniziale, ovvero puoi raggiungere ogni altro nodo nel modo più efficiente possibile.

L'algoritmo Prims ti fornisce l'MST per un dato grafo, cioè un albero che collega tutti i nodi mentre la somma di tutti i costi è il minimo possibile.

Per farla breve con un esempio realistico:

  1. Dijkstra vuole conoscere il percorso più breve per ogni punto di destinazione risparmiando tempo di viaggio e carburante.
  2. Prim vuole sapere come implementare in modo efficiente un sistema ferroviario ferroviario, risparmiando i costi dei materiali.

10

Direttamente dall'articolo di wikipedia di Dijkstra's Algorithm :

Il processo che sta alla base dell'algoritmo di Dijkstra è simile al processo avido utilizzato nell'algoritmo di Prim. Lo scopo di Prim è trovare uno spanning tree minimo che colleghi tutti i nodi nel grafo; Dijkstra si occupa solo di due nodi. Prim's non valuta il peso totale del percorso dal nodo di partenza, solo il percorso individuale.


5
"Dijkstra si occupa solo di due nodi" è a castello.
tmyklebu

5

Ultimamente sono stato infastidito dalla stessa domanda e penso di poter condividere la mia comprensione ...

Penso che la differenza chiave tra questi due algoritmi (Dijkstra e Prim) sia radicata nel problema per cui sono progettati per risolvere, vale a dire, il percorso più breve tra due nodi e il minimal spanning tree (MST). Il formale è quello di trovare il percorso più breve tra il dire, il nodo s e t , e un requisito razionale è quello di visitare ogni bordo del grafico al massimo una volta. Tuttavia, NON ci richiede di visitare tutto il nodo. Quest'ultimo (MST) è per farci visitare TUTTI il nodo (al massimo una volta) e con lo stesso requisito razionale di visitare ogni bordo al massimo una volta.

Detto questo, Dijkstra ci permette di "prendere scorciatoie" così a lungo che posso andare da s a t , senza preoccuparmi delle conseguenze - una volta arrivato a t , ho finito! Sebbene ci sia anche un percorso da s a t nell'MST, ma questo percorso s - t viene creato considerando tutti i nodi di riposo, quindi, questo percorso può essere più lungo del percorso s - t trovato dall'algoritmo di Dijstra. Di seguito è riportato un rapido esempio con 3 nodi:

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

Diciamo che ciascuno dei bordi superiori ha il costo di 2 e il bordo inferiore ha un costo di 3, quindi Dijktra ci dirà di prendere il percorso inferiore, poiché non ci interessa il nodo centrale. D'altra parte, Prim ci restituirà un MST con i 2 bordi superiori, scartando il bordo inferiore.

Tale differenza si riflette anche nella sottile differenza nelle implementazioni: nell'algoritmo di Dijkstra, è necessario avere una fase di contabilità (per ogni nodo) per aggiornare il percorso più breve da s , dopo aver assorbito un nuovo nodo, mentre nell'algoritmo di Prim, c'è non è tale bisogno.


3

La differenza fondamentale tra gli algoritmi di base risiede nei loro diversi criteri di selezione dei margini. In genere, entrambi utilizzano una coda prioritaria per selezionare i nodi successivi, ma hanno criteri diversi per selezionare i nodi adiacenti dei nodi di elaborazione correnti: l'algoritmo di Prim richiede che anche i nodi adiacenti successivi debbano essere tenuti in coda, mentre l'algoritmo di Dijkstra non:

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--------
            ...

I calcoli di vertice.distance sono il secondo punto diverso.


3

L'algoritmo di Dijkstra è un problema di percorso più breve di una singola sorgente tra i nodi ie j, ma l'algoritmo di Prim è un problema minimo di spanning tree. Questi algoritmi utilizzano un concetto di programmazione denominato "algoritmo avido"

Se controlli queste nozioni, visita

  1. Nota di lezione sull'algoritmo avido: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf
  2. Albero di copertura minimo: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/20-mst.pdf
  3. Percorso più breve da un'unica fonte: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/21-sssp.pdf

2

Algoritmo di Dijkstras viene utilizzato solo per trovare il percorso più breve.

In Minimum Spanning Tree (algoritmo di Prim o Kruskal) ottieni egdes minimi con valore minimo del bordo.

Ad esempio: - Considera una situazione in cui non vuoi creare una rete enorme per la quale richiederai un gran numero di fili, quindi questo conteggio dei fili può essere fatto usando il Minimum Spanning Tree (algoritmo di Prim o Kruskal) (cioè lo farà darti un numero minimo di cavi per creare enormi connessioni di rete cablate con un costo minimo).

Considerando che "Algoritmo Dijkstras" verrà utilizzato per ottenere il percorso più breve tra due nodi mentre si connettono i nodi tra loro.


2

La spiegazione più semplice è che in Prims non si specifica il nodo iniziale , ma in dijsktra (è necessario disporre di un nodo iniziale) è necessario trovare il percorso più breve dal nodo dato a tutti gli altri nodi.


0

@templatetypedef ha coperto la differenza tra MST e il percorso più breve. Ho coperto la differenza dell'algoritmo in un altro Quindi rispondi dimostrando che entrambi possono essere implementati utilizzando lo stesso algoritmo generico che accetta un parametro in più come input: funzione f(u,v). La differenza tra l'algoritmo di Prim e quello di Dijkstra è semplicemente ciò f(u,v)che usi.


0

A livello di codice, l'altra differenza è l'API.

Inizializzi Prim con un vertice di origine, s , ie Prim.new(s),; s può essere qualsiasi vertice e, indipendentemente da s , il risultato finale, che sono i bordi dell'albero di copertura minimo (MST), sono gli stessi. Per ottenere i bordi MST, chiamiamo il metodoedges() .

Si inizializza Dijkstra con un vertice sorgente, s , ovvero Dijkstra.new(s)si desidera ottenere il percorso / distanza più breve da tutti gli altri vertici. I risultati finali, che sono il percorso / distanza più breve da s a tutti gli altri vertici; sono diversi a seconda della s . Per ottenere i percorsi / distanze più brevi da s a qualsiasi vertice, v , chiamiamo i metodi distanceTo(v)e pathTo(v)rispettivamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.