Algoritmo di Dijkstra: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
LiveRC : Annullate le modifiche di 5.157.108.108 (discussione), riportata alla versione precedente di Nubifer Etichetta: Annulla |
Funzionalità collegamenti suggeriti: 3 collegamenti inseriti. |
||
(36 versioni intermedie di 31 utenti non mostrate) | |||
Riga 1:
{{nota disambigua|l'algoritmo per la [[mutua esclusione]] in sistemi concorrenti, detto anche "algoritmo di proiezione di Dijkstra"|
▲{{nota disambigua|l'algoritmo per la [[mutua esclusione]] in sistemi concorrenti, detto anche "algoritmo di proiezione di Dijkstra"|la voce [[algoritmo di Dekker]]}}
{{Algoritmo
|classe = [[Algoritmo di ricerca]]
|immagine = Dijkstra Animation.gif
|didascalia = Esecuzione dell'algoritmo di Dijkstra
|struttura dati = [[Grafo (tipo di dato astratto)|Grafo]]
|tempo = <math>O(|E| + |V| \log|V|)</math><ref>
|tempo migliore =
|tempo medio =
Line 13 ⟶ 12:
|completo =
}}
L
Tale algoritmo trova applicazione in molteplici contesti quale l'ottimizzazione nella
== Algoritmo ==
Supponiamo di avere un grafo con n vertici contraddistinti da numeri interi {1,2,...,n} e che
# ''Inizializzazione''.
Line 35 ⟶ 34:
==Pseudocodice==
Nel seguente algoritmo, il codice <code>u := vertici in ''Q'' con la più breve dist[]</code>, cerca per dei
1 '''function''' Dijkstra(''Grafo'', ''sorgente''):
Line 41 ⟶ 40:
3 dist[''v''] := infinito ; ''// Distanza iniziale sconosciuta''
4 ''// dalla sorgente a v''
5 precedente[''v''] := non definita ; ''// Nodo precedente in un percorso ottimale''
6 '''end for''' ''// dalla sorgente''
7
8 dist[''sorgente''] := 0 ; ''// Distanza dalla sorgente alla sorgente''
9 ''Q'' := L'insieme di tutti i nodi nel ''Grafo'' ; ''// Tutti i nodi nel grafo sono''
Line 53 ⟶ 52:
15 '''break''' ; ''// tutti i vertici rimanenti sono''
16 '''end if''' ''// inaccessibili dal nodo sorgente''
17
18 '''For each''' neighbour ''v'' di ''u'':
20 ''alt'' := dist[''u''] + dist_tra(''u'', ''v'') ;
21 '''if''' ''alt'' < dist[''v'']:
22 dist[''v''] := ''alt'' ;
23 precedente[''v''] := ''u'' ;
Line 66 ⟶ 64:
28 '''return''' dist;
Se siamo interessati solo al percorso minimo tra due
Adesso possiamo leggere il percorso più breve da <code><var>sorgente</var></code> a <code><var>destinazione</var></code> tramite un'iterazione inversa:
1 ''S'' := sequenza vuota
2 ''u'' := ''destinazione''
3 '''while''' precedente[''u''] è definito: ''// Costruisci il cammino minimo con uno stack S''
4 inserisci ''u'' all'inizio di ''S'' ''// Esegui il push del vertice sullo stack''
5 ''u'' := precedente[''u''] ''// Traverse da destinazione a sorgente.''
6 '''end while''' ;
Adesso la sequenza <code><var>S</var></code> è la lista dei
== Tempo di esecuzione ==
In generale, la complessità, <math>T_D(G)</math>, dell'algoritmo di Dijkstra è limitata superiormente da
:<math>
dove <math>T_B(|V|)</math>, <math>T_E(|V|)</math> e <math>T_U(|V|)</math> sono le complessità necessarie alle operazioni di costruzioni di una coda con <math>|V|</math> elementi, estrazione del minimo da una coda con <math>|V|</math> elementi e la riduzione di un valore in una coda con <math>|V|</math> elementi.
Di seguito sono riportate le complessità di <math>T_B(|V|)</math>, <math>T_E(|V|)</math>, <math>T_U(|V|)</math> e dell'algoritmo di Dijkstra nel caso in cui le code di priorità siano implementate tramite array, [[Heap binario|heap binarie]] o [[heap di Fibonacci]].
{| class="wikitable"
|+Complessità dell'algoritmo di Dijkstra in funzione dell'implementazione della coda di priorità
! !! Costruire la coda !! Estrarre il minimo !! Ridurre un valore !! Algoritmo di Dijkstra
|-
! Arrays
| <math>\Theta(|V|)</math> || <math>O(|V|)</math> || <math>\Theta(1)</math> || <math>O(|V|^2+|E|)</math>
|-
! [[Heap binario|Heap binarie]]
| <math>\Theta(|V|)</math> || <math>O(\log_2 |V|)</math> || <math>O(\log_2 |V|)</math> || <math>O((|V|+|E|) \log_2 |V|)</math>
|-
! [[Heap di Fibonacci]]
| <math>\Theta(|V|)</math> || <math>O(\log_2 |V|)</math><ref name="ammortizata">Analisi ammortizzata</ref> || <math>\Theta(1)</math><ref name="ammortizata"/> || <math>O(|V|\log_2 |V| + |E|)</math><ref name="ammortizata" />
|}
È interessante notare che, nel caso in cui il grafo '''non''' sia sufficientemente sparso e <math>|E| \in \Omega( |V|^2 / \log_2 |V| )</math>, la soluzione basata sugli array è più efficiente di quella implementata tramite le [[Heap binario|heap binarie]].
== Esempio ==
Alla base di questi problemi c'è lo scopo di trovare il percorso minimo (più corto, più veloce, più economico…) tra due punti, uno di partenza e uno di arrivo. Con il metodo che si vedrà è possibile ottenere non solo il percorso minimo tra un punto di partenza e uno di arrivo ma l'[[albero dei cammini minimi]], cioè tutti i percorsi minimi tra un punto di partenza e tutti gli altri punti della rete. Come per praticamente tutti i problemi riguardanti le reti la cosa migliore è fare una schematizzazione della situazione per risolvere l'esercizio più agevolmente e avere sempre a disposizione i dati necessari. Una buona schematizzazione per i problemi di percorso minimo deve includere tutti i possibili collegamenti tra i nodi (e i relativi costi) e deve essere fissato un nodo di partenza.
[[File:Ricerca operativa percorso minimo 01.gif|center]]
<div style="float:center; width:80%; padding:15px; background: #f5f8ff; border: 1px solid blue; margin-left:8px; margin-right:8px;margin-bottom:15px; text-align:left">
* Ogni nodo ha, all'inizio potenziale <math>+ \infty</math> (che indichiamo con “inf”);
* Il nodo di partenza (in questo caso “casa”) ha potenziale 0 (ovvero dista zero da
* Ogni volta si sceglie il nodo con potenziale minore e lo si rende definitivo (colorando il potenziale di rosso) e si aggiornano i nodi adiacenti;
* Il potenziale di un nodo è dato dalla somma del potenziale del nodo precedente + il costo del collegamento;
Line 109 ⟶ 118:
* Quando si aggiorna il potenziale di un nodo si lascia quello minore (essendo un problema di percorso minimo).
</div>
[[File:Ricerca operativa percorso minimo 02.gif|center]]
Seguendo le regole appena fissate
[[File:Ricerca operativa percorso minimo 03.gif|center]]
Bisogna ora considerare il nodo non definitivo (ovvero quelli scritti in nero) con potenziale minore (il nodo A). Lo si rende definitivo e si aggiornano i potenziali dei nodi adiacenti B e C.
[[File:Ricerca operativa percorso minimo 04.gif|center]]
Il nodo con potenziale minore ora è C. lo si rende definitivo e si aggiornano quelli adiacenti.
[[File:Ricerca operativa percorso minimo 05.gif|center]]
Va notato come il nodo D abbia ora potenziale 6 in quanto 6 è minore di 8 e quindi lo si aggiorna. Se
[[File:Ricerca operativa percorso minimo 06.gif|center]]
Il nodo con potenziale minore restante è B e lo si rende definitivo aggiornando di conseguenza il grafico:
Line 124 ⟶ 132:
Restano da considerare il nodo E e da aggiornare “ufficio”.
[[File:Ricerca operativa percorso minimo 08.gif|center]]
Seguendo all'indietro le frecce si ottiene il percorso minimo da casa
[[File:Ricerca operativa percorso minimo 09.gif|center]]
Bisogna notare come questo algoritmo ci dia non solo la distanza minima tra il punto di partenza e quello di arrivo ma la distanza minima di tutti i nodi da quello di partenza, da cui si può realizzare l'albero dei cammini minimi semplicemente eliminando gli archi utilizzati da nessun cammino.
Line 143 ⟶ 151:
== Altri progetti ==
{{interprogetto|
{{Algoritmi ricerca grafi}}
{{Portale|informatica|matematica}}
[[Categoria:Algoritmi di ottimizzazione|Dijkstra]]
|