mirror of
https://github.com/Steffo99/unisteffo.git
synced 2024-11-28 19:04:18 +00:00
69 lines
3 KiB
Markdown
69 lines
3 KiB
Markdown
|
# Algoritmo di Dijkstra
|
||
|
|
||
|
L'_Algoritmo di [Dijkstra](https://upload.wikimedia.org/wikipedia/commons/8/85/Dijkstra.ogg)_ è un algoritmo che risolve il problema del **percorso più breve da una sorgente singola** per grafi con pesi **reali positivi** `\mathbb{R}^+`.
|
||
|
|
||
|
L'algoritmo trova tutti i percorsi più brevi per raggiungere qualsiasi nodo del grafo partendo da un dato nodo, assieme al costo richiesto per farlo.
|
||
|
|
||
|
## Funzionamento
|
||
|
|
||
|
1. Separiamo tutti i nodi del grafo in due gruppi: **visitati** e **non visitati**.
|
||
|
- Tutti i nodi partono da **non visitati**.
|
||
|
2. Per ogni nodo, manteniamo un valore "**costo richiesto per raggiungerlo**", che verrà cambiato man mano che l'algoritmo avanza.
|
||
|
- Il costo di partenza è `+∞`.
|
||
|
- Il costo sarà **definitivo per i nodi visitati**, e **provvisorio per i non visitati**.
|
||
|
3. Creiamo un insieme detto _frontiera_ che conterrà tutti i **nodi non visitati adiacenti** a quelli visitati.
|
||
|
4. Prendiamo il nodo iniziale, che avrà un **costo di `0`**, e definiamolo il nodo _attuale_.
|
||
|
5. Finchè ci sono dei nodi non sono stati visitati, ripetiamo il seguente ciclo:
|
||
|
1. Aggiungiamo i nodi adiacenti al nodo attuale alla frontiera.
|
||
|
- Il costo per raggiungerli sarà il **costo per il nodo attuale sommato al costo dell'arco** che li connette al nodo attuale.
|
||
|
Se questo **costo** risulta essere **minore del costo provvisorio** precedente, esso **diventerà il nuovo costo**.
|
||
|
- Questa operazione è detta _rilassamento dell'arco_.
|
||
|
2. Facciamo diventare **visitato** il nodo attuale.
|
||
|
- Il percorso che abbiamo fatto per raggiungerlo è obbligatoriamente il più breve.
|
||
|
3. Il prossimo nodo attuale sarà il nodo di frontiera con un costo più basso.
|
||
|
- Per questo, è possibile definire l'algoritmo di Dijkstra come un **algoritmo greedy**.
|
||
|
|
||
|
### Non funziona se...
|
||
|
|
||
|
L'algoritmo smette di funzionare nel caso in cui siano presenti **costi negativi** e il grafo non sia **aciclico**, in quanto non saremmo mai in grado di rendere visitato un nodo.
|
||
|
|
||
|
## Costo computazionale
|
||
|
|
||
|
| Categoria | Upper bound |
|
||
|
|-----------|-------------|
|
||
|
| Tempo | `O(nodi + archi) log nodi)` |
|
||
|
|
||
|
### Scomposizione
|
||
|
|
||
|
- Inizializzazione: `O(nodi)`
|
||
|
- Creazione coda priorità: `O(nodi log nodi)`
|
||
|
- Ciclo: `O((nodi + archi) log nodi)`
|
||
|
|
||
|
## Pseudocodice
|
||
|
|
||
|
```python
|
||
|
import math
|
||
|
|
||
|
class Info:
|
||
|
def __init__(self, distance=math.inf, previous=None):
|
||
|
self.distance = distance
|
||
|
self.previous = previous
|
||
|
|
||
|
def dijkstra(graph, start):
|
||
|
data = [Info() for node in graph.nodes]
|
||
|
queue = PriorityQueue([start])
|
||
|
while queue:
|
||
|
node = queue.pop()
|
||
|
for arc in node.connections:
|
||
|
other = arc.other(node)
|
||
|
if data[node.number].distance + arc.cost < data[other].distance:
|
||
|
data[other].distance = data[node.number].distance + arc.cost
|
||
|
queue.decrease_priority_for(other, data[other].distance)
|
||
|
data[v].previous = node
|
||
|
return data
|
||
|
```
|
||
|
|
||
|
## Visualizzazione
|
||
|
|
||
|
[Visualgo](https://visualgo.net/en/sssp)
|