Articulo de referencia

Algoritmo de Floyd-Warshall

\\Theta (|V|^3) "},"average-time":{"wt":" \\Theta (|V|^3) "},"best-time":{"wt":" \\Theta (|V|^3) "},"space":{"wt":" \\Theta(|V|^2) "}},"i":0}}]}"> En informática , el algoritmo ...

En informática , el algoritmo de Floyd-Warshall (también conocido como algoritmo de Floyd , algoritmo de Roy-Warshall , algoritmo de Roy-Floyd o algoritmo WFI ) es un algoritmo para encontrar caminos más cortos en un grafo dirigido ponderado con pesos de aristas positivos o negativos (pero sin ciclos negativos). [ 1 ] [ 2 ] Una sola ejecución del algoritmo encontrará las longitudes (pesos sumados) de los caminos más cortos entre todos los pares de vértices. Aunque no devuelve detalles de los caminos en sí, es posible reconstruirlos con simples modificaciones al algoritmo. También se pueden usar versiones del algoritmo para encontrar el cierre transitivo de una relación o (en conexión con el sistema de votación de Schulze ) los caminos más amplios entre todos los pares de vértices en un grafo ponderado.

Historia y denominación

El algoritmo de Floyd-Warshall es un ejemplo de programación dinámica y fue publicado en su forma actualmente reconocida por Robert Floyd en 1962. [ 3 ] Sin embargo, es esencialmente el mismo que los algoritmos publicados previamente por Bernard Roy en 1959 [ 4 ] y también por Stephen Warshall en 1962 [ 5 ] para encontrar el cierre transitivo de un grafo, [ 6 ] y está estrechamente relacionado con el algoritmo de Kleene (publicado en 1956) para convertir un autómata finito determinista en una expresión regular , con la diferencia de que utiliza un semianillo min-plus . [ 7 ] La formulación moderna del algoritmo como tres bucles for anidados fue descrita por primera vez por Peter Ingerman, también en 1962. [ 8 ]

Algoritmo

El algoritmo de Floyd-Warshall compara muchos caminos posibles a través del grafo entre cada par de vértices. Está garantizado que encontrará todos los caminos más cortos y es capaz de hacerlo conΘ(|V|3){\displaystyle \Theta (|V|^{3})}comparaciones en un gráfico, [ 1 ] [ 9 ] aunque puede haberΘ(|V|2){\displaystyle \Theta (|V|^{2})}aristas en el grafo. Lo hace mejorando incrementalmente una estimación del camino más corto entre dos vértices, hasta que la estimación sea óptima.

Consideremos un gráficoGRAMO{\displaystyle G}con vérticesV{\displaystyle V}numerados del 1 al norte{\displaystyle N}Consideremos además una funciónshortmistPAGath(i,j,k){\displaystyle \mathrm {ruta más corta} (i,j,k)}que devuelve la longitud del camino más corto posible (si existe) desdei{\displaystyle i}aj{\displaystyle j}utilizando vértices únicamente del conjunto{1,2,,k}{\displaystyle \{1,2,\ldots ,k\}}como puntos intermedios en el camino. Ahora, dada esta función, nuestro objetivo es encontrar la longitud del camino más corto desde cada uno.i{\displaystyle i}a cadaj{\displaystyle j}usando cualquier vértice en{1,2,,norte}{\displaystyle \{1,2,\ldots ,N\}}Por definición, este es el valorshortmistPAGath(i,j,norte){\displaystyle \mathrm {ruta más corta} (i,j,N)}, que encontraremos recursivamente .

Observa queshortmistPAGath(i,j,k){\displaystyle \mathrm {ruta más corta} (i,j,k)}debe ser menor o igual queshortmistPAGath(i,j,k1){\displaystyle \mathrm {ruta más corta} (i,j,k-1)}: tenemos más flexibilidad si se nos permite usar el vérticek{\displaystyle k}. SishortmistPAGath(i,j,k){\displaystyle \mathrm {ruta más corta} (i,j,k)}es de hecho menos queshortmistPAGath(i,j,k1){\displaystyle \mathrm {ruta más corta} (i,j,k-1)}, entonces debe haber un camino desdei{\displaystyle i}aj{\displaystyle j}utilizando los vértices{1,2,,k}{\displaystyle \{1,2,\ldots ,k\}}que sea más corto que cualquier ruta de este tipo que no utilice el vérticek{\displaystyle k}Dado que no existen ciclos negativos, este camino se puede descomponer de la siguiente manera:

(1) un camino desdei{\displaystyle i}ak{\displaystyle k}que utiliza los vértices{1,2,,k1}{\displaystyle \{1,2,\ldots ,k-1\}}, seguido de
(2) un camino desdek{\displaystyle k}aj{\displaystyle j}que utiliza los vértices{1,2,,k1}{\displaystyle \{1,2,\ldots ,k-1\}}.

Y, por supuesto, debe existir un camino más corto (o varios de ellos), de lo contrario podríamos reducir aún más la longitud. En otras palabras, hemos llegado a la fórmula recursiva:

shortmistPAGath(i,j,k)={\displaystyle \mathrm {shortestPath} (i,j,k)=}
metroinorte(shortmistPAGath(i,j,k1),{\displaystyle \mathrm {min} {\Big (}\mathrm {shortestPath} (i,j,k-1),}
shortmistPAGath(i,k,k1)+shortmistPAGath(k,j,k1)){\displaystyle \mathrm {shortestPath} (i,k,k-1)+\mathrm {shortestPath} (k,j,k-1){\Big )}}.

El caso base viene dado por

shortmistPAGath(i,j,0)=w(i,j),{\displaystyle \mathrm {shortestPath} (i,j,0)=w(i,j),}

dóndew(i,j){\displaystyle w(i,j)}denota el peso del borde dei{\displaystyle i}aj{\displaystyle j}si existe uno e ∞ (infinito) en caso contrario.

Estas fórmulas son la base del algoritmo de Floyd-Warshall. El algoritmo funciona calculando primeroshortmistPAGath(i,j,k){\displaystyle \mathrm {shortestPath} (i,j,k)}a pesar de(i,j){\displaystyle (i,j)}pares parak=0{\displaystyle k=0}, entoncesk=1{\displaystyle k=1}, entoncesk=2{\displaystyle k=2}y así sucesivamente. Este proceso continúa hastak=norte{\displaystyle k=N}y hemos encontrado el camino más corto para todos(i,j){\displaystyle (i,j)}empareja utilizando cualquier vértice intermedio. A continuación se muestra el pseudocódigo para esta versión básica.

Pseudocódigo

sea ​​dist un arreglo |V| × |V| de distancias mínimas inicializado a ∞ (infinito) para cada arista ( u , v ) hacer dist[ u ][ v ] = w( u , v ) // El peso de la arista ( u , v ) para cada vértice v hacer dist[ v ][ v ] = 0 para k desde 1 hasta |V| para i desde 1 hasta |V| para j desde 1 hasta |V| si dist[ i ][ j ] > dist[ i ][ k ] + dist[ k ][ j ] dist[ i ][ j ] = dist[ i ][ k ] + dist[ k ][ j ] fin si

Nota: Un error común al implementar el algoritmo de Floyd-Warshall es ordenar incorrectamente los bucles triplemente anidados (el orden correcto es KIJ). Los algoritmos incorrectos IJKno IKJproporcionan soluciones correctas para algunas instancias. Sin embargo, podemos demostrar que si se repiten tres veces, obtenemos las soluciones correctas. [ 10 ]

Ejemplo

El algoritmo anterior se ejecuta en el gráfico de la izquierda que aparece a continuación:

Antes de la primera recursión del bucle externo, etiquetado como k = 0 arriba, los únicos caminos conocidos corresponden a las aristas individuales en el grafo. En k = 1 , se encuentran caminos que pasan por el vértice 1: en particular, se encuentra el camino [2,1,3], reemplazando el camino [2,3] que tiene menos aristas pero es más largo (en términos de peso). En k = 2 , se encuentran caminos que pasan por los vértices {1,2}. Los recuadros rojo y azul muestran cómo el camino [4,2,1,3] se construye a partir de los dos caminos conocidos [4,2] y [2,1,3] encontrados en iteraciones anteriores, con 2 en la intersección. El camino [4,2,3] no se considera, porque [2,1,3] es el camino más corto encontrado hasta ahora de 2 a 3. En k = 3 , se encuentran caminos que pasan por los vértices {1,2,3}. Finalmente, en k = 4 , se encuentran todos los caminos más cortos.

La matriz de distancias en cada iteración de k , con las distancias actualizadas en negrita , será:

Comportamiento con ciclos negativos

Un ciclo negativo es un ciclo cuyas aristas suman un valor negativo. No existe un camino más corto entre ningún par de vértices.i{\displaystyle i},j{\displaystyle j}que forman parte de un ciclo negativo, porque las longitudes de los caminos desdei{\displaystyle i}aj{\displaystyle j}puede ser arbitrariamente pequeño (negativo). Para obtener resultados numéricamente significativos, el algoritmo de Floyd-Warshall asume que no existen ciclos negativos. Sin embargo, si existen ciclos negativos, el algoritmo de Floyd-Warshall puede utilizarse para detectarlos. La idea es la siguiente:

  • El algoritmo de Floyd-Warshall revisa iterativamente las longitudes de los caminos entre todos los pares de vértices.(i,j){\displaystyle (i,j)}, incluyendo dóndei=j{\displaystyle i=j};
  • Inicialmente, la longitud del camino(i,i){\displaystyle (i,i)}es cero;
  • Un camino[i,k,,i]{\displaystyle [i,k,\ldots ,i]}Solo se puede mejorar esto si tiene una longitud menor que cero, es decir, denota un ciclo negativo;
  • Por lo tanto, después del algoritmo,(i,i){\displaystyle (i,i)}será negativo si existe un camino de longitud negativa desdei{\displaystyle i}volver ai{\displaystyle i}.

Por lo tanto, para detectar ciclos negativos utilizando el algoritmo de Floyd-Warshall, se puede inspeccionar la diagonal de la matriz de ruta, y la presencia de un número negativo indica que el grafo contiene al menos un ciclo negativo. [ 9 ] Sin embargo, cuando hay un ciclo negativo presente, durante la ejecución del algoritmo se generan números exponencialmente grandes del orden deΩ(6nortewmetroaincógnita){\displaystyle \Omega (6^{n}\cdot w_{max})}puede aparecer, dondewmetroaincógnita{\displaystyle w_{max}}es el mayor valor absoluto del peso de la arista en el grafo. Para evitar problemas de subdesbordamiento de enteros, se debe comprobar si hay un ciclo negativo dentro del bucle for más interno del algoritmo. [ 11 ]

Reconstrucción de trayectoria

El algoritmo de Floyd-Warshall normalmente solo proporciona las longitudes de los caminos entre todos los pares de vértices. Con modificaciones sencillas, es posible crear un método para reconstruir el camino real entre cualquier par de vértices extremos. Si bien uno podría inclinarse a almacenar el camino real de cada vértice a cada otro vértice, esto no es necesario y, de hecho, es muy costoso en términos de memoria. En su lugar, podemos usar el árbol de caminos más cortos , que se puede calcular para cada nodo enΘ(|mi|){\displaystyle \Theta (|E|)}tiempo usandoΘ(|V|){\displaystyle \Theta (|V|)}memoria, y nos permite reconstruir de manera eficiente un camino dirigido entre dos vértices conectados cualesquiera.

Pseudocódigo

El arreglo prev[u][v]contiene el penúltimo vértice en el camino de ua v(excepto en el caso de prev[v][v], donde siempre contiene vincluso si no hay un bucle en v): [ 12 ]

que esto sea un|V|×|V|{\displaystyle |V|\times |V|}matriz de distancias mínimas inicializadas a{\displaystyle \infty }(infinito) sea prev un|V|×|V|{\displaystyle |V|\times |V|}matriz de índices de vértices inicializada a nuloEl procedimiento FloydWarshallWithPathReconstruction () es para cada arista (u, v) hacer dist[u][v] = w(u, v) // El peso de la arista (u, v) prev[u][v] = u para cada vértice v hacer dist[v][v] = 0 prev[v][v] = v para k desde 1 hasta |V| hacer // implementación estándar de Floyd-Warshall para i desde 1 hasta |V| para j desde 1 hasta |V| si dist[i][j] > dist[i][k] + dist[k][j] entonces dist[i][j] = dist[i][k] + dist[k][j] prev[i][j] = prev[k][j]
El procedimiento Path (u, v) es si prev[u][v] = null entonces devuelve [] ruta = [v] mientras uv hacer v = prev[u][v] ruta.anteponer(v) ruta de retorno

complejidad temporal

Dejarnorte{\displaystyle n}ser|V|{\displaystyle |V|}, el número de vértices. Para encontrar todosnorte2{\displaystyle n^{2}}de shortmistPAGath(i,j,k){\displaystyle \mathrm {shortestPath} (i,j,k)}(a pesar dei{\displaystyle i}yj{\displaystyle j}) de aquellos de shortmistPAGath(i,j,k1){\displaystyle \mathrm {shortestPath} (i,j,k-1)}requiereΘ(norte2){\displaystyle \Theta (n^{2})}operaciones. Dado que comenzamos con shortmistPAGath(i,j,0)=midgramomidoost(i,j){\displaystyle \mathrm {shortestPath} (i,j,0)=\mathrm {edgeCost} (i,j)}y calcular la secuencia denorte{\displaystyle n}matricesshortmistPAGath(i,j,1){\displaystyle \mathrm {shortestPath} (i,j,1)},shortmistPAGath(i,j,2){\displaystyle \mathrm {shortestPath} (i,j,2)},{\displaystyle \ldots },shortmistPAGath(i,j,norte){\displaystyle \mathrm {shortestPath} (i,j,n)}, cada uno con un costo deΘ(norte2){\displaystyle \Theta (n^{2})}, la complejidad temporal total del algoritmo esnorteΘ(norte2)=Θ(norte3){\displaystyle n\cdot \Theta (n^{2})=\Theta (n^{3})}. [ 9 ] [ 13 ]

Aplicaciones y generalizaciones

El algoritmo de Floyd-Warshall se puede utilizar para resolver los siguientes problemas:

Implementaciones

Existen implementaciones disponibles para muchos lenguajes de programación .

  • Para C++ , en la biblioteca boost::graph
  • Para C# , en QuikGraph
  • Para C# , en QuickGraphPCL (una bifurcación de QuickGraph con mejor compatibilidad con proyectos que utilizan bibliotecas de clases portátiles).
  • Para Java , en la biblioteca Apache Commons Graph
  • Para JavaScript , en la biblioteca Cytoscape
  • Para Julia , en el paquete Graphs.jl
  • Para MATLAB , en el paquete Matlab_bgl archivado el 17 de agosto de 2013 en Wayback Machine
  • Para Perl , en el módulo Graph
  • Para Python , en la biblioteca SciPy (módulo scipy.sparse.csgraph ) o en la biblioteca NetworkX.
  • Para R , en los paquetes e1071 y Rfast
  • Para C , una implementación paralela con pthreads que incluye una interfaz SQLite para los datos en floydWarshall.h

Comparación con otros algoritmos de ruta más corta

Para grafos con pesos de aristas no negativos, el algoritmo de Dijkstra se puede utilizar para encontrar todos los caminos más cortos desde un único vértice con un tiempo de ejecuciónΘ(|mi|+|V|registro|V|){\displaystyle \Theta (|E|+|V|\log |V|)}Por lo tanto, ejecutar Dijkstra comenzando en cada vértice lleva tiempo.Θ(|mi||V|+|V|2registro|V|){\displaystyle \Theta (|E||V|+|V|^{2}\log |V|)}. Desde|mi|=O(|V|2){\displaystyle |E|=O(|V|^{2})}, esto produce un tiempo de ejecución en el peor de los casos de Dijkstra repetido deO(|V|3){\displaystyle O(|V|^{3})}. Si bien esto coincide con el tiempo de ejecución asintótico en el peor de los casos del algoritmo de Floyd-Warshall, las constantes involucradas importan bastante. Cuando un grafo es denso (es decir,|mi||V|2{\displaystyle |E|\approx |V|^{2}}), el algoritmo de Floyd-Warshall tiende a funcionar mejor en la práctica. Cuando el grafo es disperso (es decir,|mi|{\displaystyle |E|}es significativamente más pequeño que|V|2{\displaystyle |V|^{2}}), Dijkstra tiende a dominar.

Para grafos dispersos con aristas negativas pero sin ciclos negativos, se puede utilizar el algoritmo de Johnson , con el mismo tiempo de ejecución asintótico que el método de Dijkstra repetido.

También se conocen algoritmos que utilizan la multiplicación rápida de matrices para acelerar el cálculo de la ruta más corta entre todos los pares de nodos en grafos densos, pero estos suelen hacer suposiciones adicionales sobre los pesos de las aristas (como requerir que sean enteros pequeños). [ 17 ] [ 18 ] Además, debido a los altos factores constantes en su tiempo de ejecución, solo proporcionarían una mejora de velocidad con respecto al algoritmo de Floyd-Warshall para grafos muy grandes.

Referencias

  1. ^ Cormen , Thomas H .; Leiserson, Charles E .; Rivest, Ronald L. (1990). Introducción a los algoritmos (1ª  ed.). MIT Press y McGraw-Hill. ISBN 0-262-03141-8.Véase en particular la Sección 26.2, "El algoritmo de Floyd-Warshall", págs.  558-565 y la Sección 26.4, "Un marco general para resolver problemas de caminos en grafos dirigidos", págs.  570-576.
  2. Kenneth H. Rosen (2003). Matemáticas discretas y sus aplicaciones, 5.ª edición . Addison Wesley. ISBN 978-0-07-119881-3.
  3. Floyd, Robert W. (junio de 1962). "Algoritmo 97: Camino más corto" . Communications of the ACM . 5 (6): 345. doi : 10.1145/367766.368168 . S2CID 2003382 . 
  4. ^ Roy, Bernard (1959). "Transitivité et connexité" . CR Acad. Ciencia. París (en francés). 249 : 216-218 .
  5. Warshall, Stephen (enero de 1962). "Un teorema sobre matrices booleanas" . Journal of the ACM . 9 (1): 11– 12. doi : 10.1145/321105.321107 . S2CID 33763989 . 
  6. Weisstein, Eric W. "Algoritmo de Floyd-Warshall" . MathWorld .
  7. Kleene, SC (1956). "Representación de eventos en redes nerviosas y autómatas finitos". En CE Shannon y J. McCarthy (eds.). Estudios de autómatas . Princeton University Press. págs. 3–42 . 
  8. Ingerman, Peter Z. (noviembre de 1962). "Algoritmo 141: Matriz de ruta" . Communications of the ACM . 5 (11): 556. doi : 10.1145/368996.369016 . S2CID 29010500 . 
  9. 1 2 3 Hochbaum, Dorit (2014). "Sección 8.9: Algoritmo de Floyd-Warshall para todos los pares de caminos más cortos" (PDF) . Apuntes de clase para IEOR 266: Algoritmos de grafos y flujos de red . Departamento de Ingeniería Industrial e Investigación Operativa, Universidad de California, Berkeley . págs. 41–42 . 
  10. Hide, Ikumi (2019). "Las implementaciones incorrectas del algoritmo de Floyd-Warshall dan soluciones correctas después de tres repeticiones". arXiv : 1904.01210 [ cs.DS ].
  11. Stefan Hougardy (abril de 2010). "El algoritmo de Floyd-Warshall en grafos con ciclos negativos". Information Processing Letters . 110 ( 8–9 ): 279–281 . doi : 10.1016/j.ipl.2010.02.001 .
  12. "Libro gratuito de algoritmos" .
  13. Baras, John; Theodorakopoulos, George (2022). Problemas de caminos en redes . Springer International Publishing. ISBN 9783031799839.
  14. Gross, Jonathan L.; Yellen, Jay (2003). Manual de teoría de grafos . Matemáticas discretas y sus aplicaciones. CRC Press. pág. 65. ISBN  9780203490204..
  15. Peñaloza, Rafael. «Estructuras algebraicas para el cierre transitivo» . Seminario «Algoritmos de grafos» . Universidad Tecnológica de Dresde, Departamento de Informática, Instituto de Informática Teórica. Archivado del original el 22 de octubre de 2009.
  16. Gillies, Donald (1993). Programación de tareas con restricciones de precedencia AND/OR (Tesis doctoral, Apéndice B) (PDF) (Informe).
  17. Zwick, Uri (mayo de 2002). "Todos los caminos más cortos entre pares usando conjuntos puente y multiplicación de matrices rectangulares". Journal of the ACM . 49 (3): 289– 317. arXiv : cs/0008011 . doi : 10.1145/567112.567114 . S2CID 1065901 . .
  18. Chan, Timothy M. (enero de 2010). "Más algoritmos para encontrar los caminos más cortos entre todos los pares de nodos en grafos ponderados". SIAM Journal on Computing . 39 (5): 2075– 2089. CiteSeerX 10.1.1.153.6864 . doi : 10.1137/08071990x . .
  • Animación interactiva del algoritmo de Floyd-Warshall.
  • Animación interactiva del algoritmo de Floyd-Warshall (Universidad Técnica de Múnich)