Algoritmo di Floyd-Warshall
Da Wikipedia, l'enciclopedia libera
L'algoritmo di Floyd-Warshall calcola il cammino minimo per tutte le coppie di un grafo pesato e orientato con una complessità [1]. L'idea alla base di questo algoritmo è un processo iterativo che, scorrendo tutti i nodi, ad ogni passo h si ha (data una matrice A) nella posizione [i,j] la distanza - pesata - minima dal nodo di indice i a quello j attraversando solo nodi di indice minore o uguale a h. Se non vi è collegamento allora nella cella c'è infinito. Alla fine (con h = numero di nodi) leggendo la matrice si ricava la distanza minima fra i vari nodi del grafo.
Algoritmo di Floyd-Warshall | |
---|---|
Classe | Algoritmo di ricerca |
Struttura dati | Grafo |
Caso peggiore temporalmente | O(|V|3) |
Caso ottimo temporalmente | Ω(|V|3) |
Caso peggiore spazialmente | Θ(|V|2) |
Premesso ciò, si può dire che il problema si risolve in programmazione dinamica facendo uso teoricamente di una matrice cubica dove le ordinate e le ascisse sono i e j, mentre h è la profondità. Praticamente, invece, possiamo usare una sola matrice reiterandola piano per piano in h. Si comincia col ricavare la matrice di adiacenza del grafo (infinito dove non vi è collegamento), poi basandoci su di essa cominciamo, in ogni passo h successivo si esaminano ogni cella[i,j] della matrice A: se la somma della distanza tra i ed il nuovo nodo in esame h sommata alla distanza fra h e j è minore della distanza direttamente fra i e j allora si sostituisce quest'ultimo con la precedente somma (per andare dal nodo i al nodo j mi conviene passare per il nodo h).
Detto in modo un po' più formale se (Ah-1[i,h] + Ah-1[h,j]) < Ah-1[i,j] allora Ah[i,j] = (Ah-1[i,h] + Ah-1[h,j]) dove h è il piano che stiamo analizzando.
Sotto potete vedere un algoritmo in pseudocodice del procedimento descritto:
Inizializzazione int [0..n, 0..n] dist; for i := 1 to n for j := 1 to n dist[i][j] := Weight(i,j);
dove Weight(i,j) è una funzione che riporta il peso dell'arco da i a j, 0 nel caso in cui i = j oppure infinito se non esiste un arco da i da j nel grafo.
floydWarshall(int [0..n, 0..n] dist) { for h := 1 to n for i := 1 to n for j := 1 to n if (dist[i][j] > dist[i][h] + dist[h][j]) then dist[i][j] := dist[i][h] + dist[h][j];
Ricostruzione dei Cammini Minimi
Riepilogo
Prospettiva
Al termine della procedura sopra riportata abbiamo solamente ottenuto il peso del cammino minimo tra ogni coppia di nodi, ma non sappiamo ancora quali siano effettivamente i nodi che formano tali cammini. Per ottenere anche il percorso si fa uso di un'ulteriore struttura dati dove memorizziamo, per ogni coppia (i,j) il predecessore di j nel cammino minimo che li collega. In fase di inizializzazione, ovviamente, il predecessore di j nel cammino minimo i → j è i. L'algoritmo si modifica leggermente introducendo questo nuovo elemento:
# inizializzazione int [0..n, 0..n] dist; int [0..n, 0..n] pred; for i := 1 to n for j := 1 to n dist[i][j] := Weight(i,j); pred[i][j] := i; endfor endfor # floyd-warshall for h := 1 to n for i := 1 to n for j := 1 to n if (dist[i][j] > dist[i][h] + dist[h][j]) then dist[i][j] := dist[i][h] + dist[h][j]; pred[i][j] := pred[h][j]; endif endfor endfor endfor
Se il cammino minimo tra i e j passa per il nodo h allora il predecessore di j in i→j sarà chiaramente il predecessore di j in h→j.
Una volta ottenuta la struttura dati pred possiamo ricostruire i cammini minimi tra ogni coppia di nodi. Supponiamo di voler ricostruire il cammino minimo P1,5 e che questo sia 1,3,4,5. Utilizziamo pred in questo modo:
- Partiamo da pred[1][5], vale 4
- Consideriamo ora pred[1][4], vale 3
- Ora pred[1][3], che vale 1: Cammino ricostruito.
Note
Bibliografia
Voci correlate
Altri progetti
Collegamenti esterni
Wikiwand - on
Seamless Wikipedia browsing. On steroids.