1
Fork 0
mirror of https://github.com/Steffo99/appunti-magistrali.git synced 2024-11-22 10:44:17 +00:00
appunti-steffo/2 - Algoritmi e strutture dati/1 - Appunti/25 - Algoritmo di Dijkstra.md

3 KiB

Algoritmo di Dijkstra

L'Algoritmo di Dijkstra è 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

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