Ricerca…


Algoritmo di percorso più breve di tutte le coppie

L'algoritmo di Floyd-Warshall è per la ricerca di percorsi più brevi in ​​un grafico ponderato con pesi di bordo positivi o negativi. Una singola esecuzione dell'algoritmo troverà le lunghezze (pesi sommati) dei percorsi più brevi tra tutte le coppie di vertici. Con una piccola variazione, può stampare il percorso più breve e può rilevare cicli negativi in ​​un grafico. Floyd-Warshall è un algoritmo di programmazione dinamica.

Diamo un'occhiata a un esempio. Applicheremo l'algoritmo di Floyd-Warshall su questo grafico: Esempio grafico

La prima cosa che facciamo è prendere due matrici 2D. Queste sono matrici di adiacenza . La dimensione delle matrici sarà il numero totale di vertici. Per il nostro grafico, prenderemo 4 * 4 matrici. La Distance Matrix sta per memorizzare la distanza minima trovata finora tra due vertici. All'inizio, per i bordi, se c'è un margine tra uv e la distanza / peso è w , memorizzeremo: distance[u][v] = w . Per tutti i bordi che non esistono, metteremo l' infinito . La Path Matrix serve a rigenerare il percorso di minima distanza tra due vertici. Quindi, inizialmente, se v'è un percorso tra u e v, stiamo andando a mettere path[u][v] = u . Questo significa che il modo migliore per arrivare a vertice-v da vertice-u è usare il bordo che connette v con u . Se non ci sono percorsi tra due vertici, inseriremo N indicando che non esiste alcun percorso disponibile ora. Le due tabelle per il nostro grafico saranno simili a:

+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|     |  1  |  2  |  3  |  4  |            |     |  1  |  2  |  3  |  4  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  1  |  0  |  3  |  6  |  15 |            |  1  |  N  |  1  |  1  |  1  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  2  | inf |  0  | -2  | inf |            |  2  |  N  |  N  |  2  |  N  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  3  | inf | inf |  0  |  2  |            |  3  |  N  |  N  |  N  |  3  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  4  |  1  | inf | inf |  0  |            |  4  |  4  |  N  |  N  |  N  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
            distance                                     path

Poiché non vi è alcun loop, le diagonali sono impostate N. E la distanza dal vertice stesso è 0 .

Per applicare l'algoritmo di Floyd-Warshall, selezioneremo un vertice medio k . Quindi, per ogni vertice i , controlleremo se possiamo passare da i a ke poi da k a j , dove j è un altro vertice e minimizzare il costo di passare da i a j . Se la distanza attuale [i] [j] è maggiore della distanza [i] [k] + distanza [k] [j] , metteremo la distanza [i] [j] uguale alla somma di queste due distanze . E il percorso [i] [j] sarà impostato su path [k] [j] , poiché è meglio passare da i a k , e quindi da k a j . Tutti i vertici saranno selezionati come k . Avremo 3 cicli annidati: per k che va da 1 a 4, i che va da 1 a 4 e j che va da 1 a 4. Stiamo andando controllo:

if distance[i][j] > distance[i][k] + distance[k][j]
    distance[i][j] := distance[i][k] + distance[k][j]
    path[i][j] := path[k][j]
end if

Quindi quello che stiamo fondamentalmente controllando è, per ogni coppia di vertici, otteniamo una distanza più breve passando da un altro vertice? Il numero totale di operazioni per il nostro grafico sarà 4 * 4 * 4 = 64 . Ciò significa che stiamo andando a fare questo controllo 64 volte. Diamo un'occhiata ad alcuni di loro:

Quando k = 1 , i = 2 e j = 3 , la distanza [i] [j] è -2 , che non è maggiore della distanza [i] [k] + distanza [k] [j] = -2 + 0 = -2 . Quindi rimarrà invariato. Di nuovo, quando k = 1 , i = 4 e j = 2 , distanza [i] [j] = infinito , che è maggiore della distanza [i] [k] + distanza [k] [j] = 1 + 3 = 4 . Quindi inseriamo la distanza [i] [j] = 4 e inseriamo il percorso [i] [j] = percorso [k] [j] = 1 . Ciò significa che, per passare dal vertice-4 al vertice-2 , il percorso 4-> 1-> 2 è più corto del percorso esistente. Questo è il modo in cui popoliamo entrambe le matrici. Il calcolo per ogni passaggio è mostrato qui . Dopo aver apportato le modifiche necessarie, le nostre matrici saranno simili a:

+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|     |  1  |  2  |  3  |  4  |            |     |  1  |  2  |  3  |  4  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  1  |  0  |  3  |  1  |  3  |            |  1  |  N  |  1  |  2  |  3  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  2  |  1  |  0  | -2  |  0  |            |  2  |  4  |  N  |  2  |  3  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  3  |  3  |  6  |  0  |  2  |            |  3  |  4  |  1  |  N  |  3  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
|  4  |  1  |  4  |  2  |  0  |            |  4  |  4  |  1  |  2  |  N  |
+-----+-----+-----+-----+-----+            +-----+-----+-----+-----+-----+
            distance                                     path

Questa è la nostra matrice di distanza più breve. Ad esempio, la distanza più breve da 1 a 4 è 3 e la distanza più breve tra 4 e 3 è 2 . Il nostro pseudo-codice sarà:

Procedure Floyd-Warshall(Graph):
for k from 1 to V     // V denotes the number of vertex
    for i from 1 to V
       for j from 1 to V
           if distance[i][j] > distance[i][k] + distance[k][j]
               distance[i][j] := distance[i][k] + distance[k][j]
               path[i][j] := path[k][j]
           end if
       end for
    end for
end for

Stampa del percorso:

Per stampare il percorso, controlleremo la matrice Path . Per stampare il percorso da u a v , inizieremo dal percorso [u] [v] . Continueremo a cambiare v = path [u] [v] finché non troviamo path [u] [v] = u e spingere tutti i valori di path [u] [v] in uno stack. Dopo aver trovato u, noi lo stamperemo u e cominciamo popping elementi dalla pila e stamparli. Questo funziona perché la matrice del percorso memorizza il valore del vertice che condivide il percorso più breve per v da qualsiasi altro nodo. Lo pseudo-codice sarà:

Procedure PrintPath(source, destination):
s = Stack()
S.push(destination)
while Path[source][destination] is not equal to source
    S.push(Path[source][destination])
    destination := Path[source][destination]
end while
print -> source
while S is not empty
    print -> S.pop
end while

Individuazione del ciclo del bordo negativo:

Per scoprire se c'è un ciclo di bordo negativo, dovremo controllare la diagonale principale della matrice delle distanze . Se qualsiasi valore sulla diagonale è negativo, significa che c'è un ciclo negativo nel grafico.

Complessità:

La complessità dell'algoritmo di Floyd-Warshall è O (V³) e la complessità spaziale è: O (V²) .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow