Universidad Nacional Autónoma de México
Facultad de Ingeniería
Algoritmos y Estructuras de Datos
Trabajo: Algoritmo de Floyd
Arrieta Peralta José Carlos
2012-1
Introducción Por principio se podría decir que un grafo es básicamente un objeto geométrico aunque en realidad sea un objeto combinatorio, es decir, un conjunto de puntos y un conjunto de líneas tomado de entre el conjunto de líneas que une cada par de vértices. Por otro lado, debido a su generalidad y a la gran diversidad de formas que pueden usarse, resulta complejo tratar con todas las ideas relacionadas con un grafo. Para facilitar el estudio de este tipo de dato, a continuación se realizará un estudio de la teoría de grafos desde el punto de vista de las ciencias de la computación, describiéndose en este trabajo el algoritmo de Floyd-Warshall que compara todos los posibles caminos a través del grafo entre cada par de vértices así encontrando la distancia más corta entre dos puntos. En lugar de buscar los caminos mínimos de un vértice a los demás nos podemos plantear buscar el camino más corto entre cualquier pareja de vértices, es decir, dado un grafo dirigido etiquetado G = {V, A} en el que las etiquetas son no negativas encontrar el camino de longitud " más corta entre dos vértices cualesquiera de ese grafo. Podría pensarse, para resolver el problema, en aplicar el algoritmo de Dijkstra n veces, una por vértice, pero en lugar de eso, aplicaremos un nuevo algoritmo creado por Floyd que va encontrando los caminos de forma iterativa. Cómo funciona el algoritmo Para este algoritmo tenemos la siguiente notación: V = {1, ..., n} conjunto de vértices. A es una matriz de tamaño n x n en la que se calculará en cada A ij la longitud más corta del camino que va de i a j. P es una matriz de tamaño n x n que utilizaremos para recuperar los caminos más cortos. C es una matriz de dimensión n x n conteniendo los costos de los arcos. Si no existe arco de un vértice i a otro j el correspondiente valor C [i,j] = . Inicialmente A [i,j] = { C[i,j] si i
j, 0 si i = j }.
A continuación se itera sobre A n veces de forma que tras hacer la k iteración A[i,j] tiene un valor correspondiente a la longitud más pequeña de cualquier camino de i a j que no pase por un vértice de índice mayor que k, es decir, cualquier vértice
intermedio entre i y j (extremos del camino) ha de ser menor o igual que k. Por tanto en cada iteración k se usará la siguiente fórmula:
Ak [i,j] = min(Ak-1 [i,j] ,Ak-1 [i,k] +Ak-1l [k,j])3 es decir, cada A k [i,j] se obtiene comparando Ak-1 [i,j], el coste de ir de i a j sin pasar por k o cualquier vértice de índice mayor, con A k1 [i,k] +Ak-1 [k,j], el costo de ir primero de i a k y después de k a j sin pasar por un vértice de índice mayor que k de forma que si el paso por el vértice k produce un camino i más corto que el indicado por A k-1 [i,j], se elige ese coste para A k [i,j] .Así mismo, cada iteración P [i,j] contendrá el vértice k que permitió al algoritmo de Floyd encontrar el valor más pequeño de A[i, j] .Inicialmente P[i,j] = 0, puesto que inicialmente el camino más corto de i a j es el propio arco. El algoritmo sería el siguiente: Algoritmo Floyd()
1. for (i = 1; i <= n; i++ ) for (j = 1; j <=n ; j++) { A[i, j]= C[i, j] P[i, j]= 0 }
2. for (i = 1; i <= n; i++) A[i, i]= 0
3. for (k = 1; k <= n; k++) for (i = 1; i <= n; i++) for (j = l; j <=n ; j++)
if ((i
j) && (A[i,k]+A[k,j] < A[i, j]))
{ A[i, j]= A[i, k]+A[k, j] P[i, j]= k }
Veamos un ejemplo con el siguiente grafo:
A0 = 0 5
P0 = 7 0 * * *
* 2 0 3 7
5 * * 0 *
* 6 * * 0
A1 = 0 5
5
7 0 [12] * *
* 2 0 3 7
5 * 10 0 *
* 6 * * 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 [1] 0 0
0 0 0 0 0
0 0 [1] 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
[2] 0 0 0 0
0 0 1 0 0
2 0 [2] 0 0
0 3 0 [3] [3]
0 0 1 [3] [3]
2 0 0 0 0
0 3 1 0 [3]
2 0 2 [3] 0
P2 = 7 0 12 * *
[9] 2 0 3 7
5 * 10 0 *
[13] 6 [18] * 0
A3 = 0 [7] 5 [8] [12]
0 0 0 0 0
P1 =
A2 = 0
0 0 0 0 0
P3 = 7 0 12 [15] [19]
9 2 0 3 7
5 [12] 10 0 [17]
13 6 18 [21] 0
A4 =
P4 =
0 7 5 8 12
7 0 12 15 19
[8] 2 0 3 7
5 12 10 0 17
0 3 0 3 3
13 6 18 21 0
A5 =
0 0 1 3 3
[4] 0 0 0 0
0 3 1 0 3
2 0 2 3 0
P5 =
0 7 8 7 0 2 5 12 0 8 15 3 12 19 7 los caminos de procedimiento:
5 13 12 6 10 18 A5 =A4 con la que el 0 21 algoritmo termina. Con 17 0 objeto de recuperar cualquier vértice i a cualquier otro
0 0 4 3 0 0 0 1 0 3 3 0 3 3 0 j puede usarse
0 2 3 0 1 2 0 3 3 0 el siguiente
Algoritmo recuperar_camino (i, j de tipo vértice)
1.k= P[i, j]
2. if (k
0)
{ recuperar_camino (i, k) escribir (k) recuperar_camino (k, j) } Por ejemplo, el camino más corto entre los vértices 2 y 4 se determinaría llamando a: recuperar-camino (2,4)
k = 3 -> recuperar-camino (2,3) -> 0
[3] recuperar-camino (3,4) -> k = 1 -> recuperar-camino (3,1) -> 0 [1] recuperar-camino (1,4) -> 0 con la que el camino es (2,3,1,4) con costo 12.
Análisis(propias palabras) : Para fabricar la matriz A del distancia tenemos que ver las conexiones y caminos para llegar a los vértices se pone el peso de la arista y así se va fabricando la matriz si un nodo esta direccionado solo puede haber dato en la dirección que marque e la flecha y al contrario de la dirección se le pone y de igual manera en vértices que no estén conectados. Para la matriz P que es de recorrido se va llenando según la iteración que valla y si en dicha iteración se modifican el valor de algún dato ya sean datos dados o los . ∞
∞
Para empezar a llenar la matriz de distancia tendremos hacer iteraciones en la primera se tachan la fila 1 y la columna 1 las casillas que quedan libres se van modificando solo si las suma de sus componentes que se obtienen de la fila y columna tachada si es menor al dato que se encuentra se cambia y si es mayor se deja igual (por ejemplo si en elemento de la matriz [2,2] hay un 4 y el elemento de la matriz [1,2] = 1 y el de [2,1]=2 como la suma de estas en menor al dato del elemento [2,2] se cambia el valor a 3 y en la matriz de recorrido se pone el 1 en la misma posición del dato modificado) es y si se cambia se pone el 1 por ser la primera iteración en la matriz de recorrido. Para la segunda iteración se tachan la fila 2 y la columna 2 y las casillas que queden libres se van modificando según sea el caso respecto a la fila y columna tachadas y ahora en lugar de ponerle un 1 en la matriz de recorrido se le pone un 2 por ser la segunda iteración Para n iteración se tacha n fila y n columna y se van modificando las casillas que no fueron tachadas si alguna se modifica en la matriz recorrido se pone la n-esima iteración según sea el caso y recordar que para que se modifique una casilla u elemento de la matriz es necesario que la suma de los elementos correspondientes tachados al alumno de la matriz sea menor.
Ya terminada de hacer las iteraciones para ver cuál es la menor distancia entre dos vértice nos vamos a la intersección de los elemento dejar en claro que para buscar la mínima distancia se tiene que empezar por las filas y después en las columnas como es un grafo dirigido es diferente y la intersección de ambos es la distancia mínima que hay entre los vértices y gracias a la matriz recorrido podemos ver cuáles son los nodos por lo que tenemos que pasar esto es colocándonos en la intersección de la en la matriz recorrido de los nodos que queramos su distancia mínima se ubica y de allí hacia arriba sobre esa misma fila para ver cuál es el recorrido que tuvimos que hacer para llegar de un nodo n a un nodo m.
Análisis de la complejidad Se deben construir n matrices de tamaño nxn y cada elemento se halla en tiempo constante. Por tanto, la complejidad del algoritmo es O (n3 ) El algoritmo de Floyd -Warshall es mucho más eficiente desde el punto de vista de almacenamiento dado que puede ser implementado una vez actualizado la distancia de la matriz con cada elección en k ; no hay ninguna necesidad de almacenar matrices diferentes. En muchas aplicaciones específicas, es más rápido que cualquier versión de algoritmo de Dijkstra .
Conclusiones: Pues una de las ventajas es que cuando terminas de hacer todas la iteraciones en la matriz encuentras las distancias mínimas de un vértice a otro y ya solo tienes que consultar la matriz el problema que que si son muchos vértices la matriz crece de igual manera por lo tanto las iteraciones también si tuviéramos por decir 100 ciudades tendíamos una matriz de 100 por 100 y el mismo número de iteraciones lo cual lo aria muy laborioso por consiguiente no muy práctico su ventaja solo podría ser para casos donde allá muy pocos vértices.