Vous êtes sur la page 1sur 9

Algoritmo de Warshall

Introduccin
El algoritmo de Floyd-Warshall es un algoritmo de anlisis de grafos para que, de forma eficiente y simultanea, encuentre los caminos ms cortos dentro de un grafo en el cual las aristas tengan un costo (distancia entre nodo y nodo, duracin del viaje entre nodos, etc.). Al ejecutar el algoritmo encontrara el camino menor o ms corto de entre todos los pares de vrtices, pero no devuelve los detalles de los caminos en si. El algoritmo es un ejemplo de la Programacin Dinmica y su variacin ms conocida fue publicada en 1962 por Robert Floyd. Aunque es necesario comentar tambin que es esencialmente el mismo algoritmo descubierto independientemente y antes publicado por Bernard Roy en 1959 y por Stephen Warshall en 1962. De ah sus mltiples pseudnimos: Algoritmo de Floyd, Algoritmo de Roy-Floyd, Algoritmo de Roy-Warshall, Algoritmo WFI.

En qu consiste?
El algoritmo de Floyd-Warshall compara todos los posibles caminos entre cada par de nodos. Esto se consigue al ir mejorando un estimado de la distancia entre dos nodos, hasta que el estimado es optimo. Considerar un grafo G con nodos o vrtices V, cada una numerada de 1 a N, adems de una funcin que al ingresar i, j, k devuelve el camino ms corto entre i y j pasando solo por el conjunto {1, 2,, k}. Ahora, utilizando esta funcin, el objetivo es encontrar el camino ms corto entre i para cada j usando solo los vrtices 1 hasta k+1. Existen dos candidatos para cada uno de esos caminos: o el verdadero camino ms corto pasando por los nodos {1,, k}; o existe un camino que vaya desde i hasta k+1, despus de k+1 hasta j que es mejor. Sabemos que el mejor camino de i a j que solo usa los nodos desde 1 hasta k est definido por la funcin anterior, y est claro que si existiera un camino desde i hasta k+1 hasta j, entonces el valor de este camino seria la concatenacin de el camino ms corto de i hasta k+1 (usando vrtices {1,, k}) y el camino ms corto desde k+1 hasta j (tambin usando vrtices {1,, k}). Si v(i, j) es el valor o costo de la arista entre los nodos i y j, podemos definir la funcin ahora llamada caminoCorto(i,j,k) en los trminos de la siguiente formula recursiva: el caso base seria caminoCorto(i,j,0) = v(i,j) y el caso recursivo seria caminoCorto(i,j,k)= min(caminoCorto(i,j,k-1), caminoCorto(i,k,k-1)+ caminoCorto(k,j,k-1). Esta frmula es el corazn del algoritmo de Floyd-Warshall. El algoritmo funciona primero calculando la funcin para todos los pares (i,j) para k=1, despus k=2, etc. Este proceso continua hasta k=n; y hemos encontrado el camino ms corto para todos los pares (i, j) usando cualquier nodo intermedio.

En qu casos se usa?
El algoritmo de Floyd-Warshall puede ser usado para resolver los siguientes problemas, entre otros. Caminos cort en un grafo dirigido (Algoritmo de Floyd). Clausura transitiva de grafos dirigidos (Algoritmo de Warshall). En el algoritmo original de Warshall el grafo no tiene aristas con coste o valor y es representado por una matriz Booleana de proximidad. Entonces la operacin de suma es remplazada por la aritmtica Booleana AND y la operacin de mnimo es remplazada por OR. Bsqueda de expresiones regulares dependiendo del lenguaje regular aceptado por una autmata finito (Algoritmo de Kleene). Inversin de matrices de nmeros reales (Algoritmo de Gauss-Jordan). Planeamiento optimo de rutas. En esta aplicacin uno est interesado en encontrar la ruta con el mximo trfico entre dos vrtices. Esto significa que, en vez de tomar el mnimo, en su lugar uno toma el mximo. El coste de arista representa la constante de flujo. los costes de caminos representan cuellos de botella; as que la operacin de adicin es reemplazada por la operacin de mnimo. Probar si un grafo indirecto es bipartito (Un Grafo bipartito se denomina en Teora de grafos a un grafo cuyos vrtices se pueden separar en dos conjuntos disjuntos V1 y V2 y las aristas siempre unen vrtices de un conjunto con vrtices de otro). Calculo rpido de redes de organizacin de datos.

Caractersticas
Obtiene la mejor ruta entre todo par de nodos. Trabaja con la matriz D inicializada con las distancias directas entre todo par de nodos. La iteracin se produce sobre nodos intermedios, o sea para todo elemento de la matriz se prueba si lo mejor para ir de i a j es a travs de un nodo intermedio elegido o como estaba anteriormente, y esto se prueba con todos los nodos de la red. Una vez probados todos los nodos de la red como nodos intermedios, la matriz resultante da la mejor distancia entre todo par de nodos. El algoritmo da slo la menor distancia; se debe manejar informacin adicional para encontrar tablas de encaminamiento. Hasta no hallar la ltima matriz no se encuentran las distancias mnimas. Su complejidad es del orden de N3.

Ejemplos Problema Real

La Empresa Afautesa cuenta 7 con bodegas distribuidoras de aguacate en el pas. Los administradores desean saber el costo mnimos de flete de una bodega a otra sin importar la bodega que enva y la bodega que recibe, esto para optimiza recursos a la hora que se transporta el producto.

Algoritmo:
Dado un grafo G(V,A) se puede aplicar el algoritmo de Floyd para resolver el problema de encontrar el camino ms corto de todos los vrtices entre s. Inicio Armar la matriz de adyacencia F, teniendo en cuenta que F(i,j)=0 si i = j (diagonal principal es 0). Adems dnde no exista camino se debe indicar con infinito. Para k desde 1 hasta n Para i desde 1 hasta n Para j desde 1 hasta n F[i,j]=min(F[i,j], F[i,k] + F[k,j]) Fin para j Fin para i Fin para k

En la k-esima vuelta F[i, j] contendr el valor del camino ms corto que una al vrtice i con el j tal que dicho camino no pase por un vrtice con nmero mayor que k. La matriz resultante es la de los mnimos caminos entre cada nodo. Si se quiere saber cual es dicho camino, se debe armar un rbol a medida tomando como numero de nodo a k cada vez que se detecta que hubo una optimizacin. Debido a su triple ciclo anidado es obviamente O(N^3).

Pseudocdigo:
Floyd-Warshall (G) n=|V [G]| for (int i=1; i<=numeroNodos; i++) for (int j=1; j<=numeroNodos; j++) si Hay conexin MatrizdePeso[i][j]=peso; else MatrizdePeso[i][j]=infinito; MatrizNodoIntermedio[i][j]=j; Si i=j MatrizNodoIntermedio[i][j]=0; MatrizdePeso[i][j]=0; for(int k=1;k<=numeroNodos;k++) for (int i=1;i<=numeroNodos;i++) for (int j=1;j<=numeroNodos;j++) a=MatrizdePeso[i][k]+MatrizdePeso[k][j]; if(a<MatrizdePeso[i][j]) { MatrizdePeso[i][j]=a; MatrizNodoIntermedio[i][j]=k; } return MatrizdePeso, MatrizNodoIntermedio;

Ejemplo:

Resultados luego de aplicar el algoritmo:

Matriz de Distancias mnimas: N1\N2 0 1 2 3 4 0 0 11 11 9 7 1 8 0 19 3 15 2 9 1 0 4 6 3 5 2 16 0 12 4 7 4 4 2 0

Matriz de Caminos: N1\N2 0 1 2 3 4 0 4 4 4 4 1 3 3 3 3 2 1 1 1 4 3 0 1 0 0 4 3 3 2 3 -

Listado de Caminos: 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 --(0)--> --(8)--> --(9)--> --(5)--> --(7)--> --(11)--> --(0)--> --(1)--> --(2)--> --(4)--> --(11)--> --(19)--> --(0)--> --(16)--> --(4)--> --(9)--> --(3)--> --(4)--> --(0)--> --(2)--> --(7)--> --(15)--> --(6)--> --(12)--> --(0)--> 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 = = = = = = = = = = = = = = = = = = = = = = = = =

0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,

3, 3, 3 3, 3,

1 1, 2 4 4, 0

2 3 3, 4 4, 0 4, 0, 3, 1 4, 0, 3 4 4, 0 1 1, 2 4 0 0, 3, 1 2 0, 3

import java.io.BufferedReader; 002.import java.io.IOException; 003.import java.io.InputStreamReader; 004. 005.public final class Grafo { 006. 007.private int nnodos; 008. 009.private int nodos[][][]; 010. 011.private char nombres[]; 012. 013.Grafo(int n) { 014.this.nnodos = n; 015.this.nodos = new int[nnodos][nnodos][2]; 016.this.nombres = new char[nnodos]; 017.} 018. 019.public void ingresarArco(int n1, int n2, int peso) { 020.this.nodos[n1][n2][0] = peso; 021.this.nodos[n2][n1][0] = peso; 022.this.nodos[n1][n2][1] = n1; 023.this.nodos[n2][n1][1] = n2; 024.} 025. 026.public void ingresarNombre(int nodo, char letra) { 027.this.nombres[nodo] = letra; 028.} 029. 030.public void calcular() { 031.int i, j, k; 032.for (i = 0; i < this.nnodos; i++) { 033.for (j = 0; j < this.nnodos; j++) { 034.for (k = 0; k < this.nnodos; k++) { 035.if (this.nodos[i][k][0] + this.nodos[k][j][0] < this.nodos[i][j][0]) { 036.this.nodos[i][j][0] = this.nodos[i][k][0] 037.+ this.nodos[k][j][0]; 038.this.nodos[i][j][1] = k; 039.} 040.} 041.} 042.} 043.} 044. 045.public int pesominimo(int org, int des) { 046.return this.nodos[org][des][0]; 047.} 048. 049.public String caminocorto(int org, int des) { 050.String cam; 051.if (org == des) { 052.cam = "->" + nombres[org]; 053.} else { 054.cam = caminocorto(org, this.nodos[org][des][1]) + "->" 055.+ nombres[des]; 056.} 057.return cam; 058.} 059. 060.public char getNombre(int nodo) { 061.return this.nombres[nodo]; 062.}

063. 064.public static void main(String args[]) throws IOException { 065.Grafo g; 066. 067.BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 068.String temp; 069.int res; 070. 071.System.out.println("Entre el numero de nodos del grafo:\n"); 072.temp = br.readLine(); 073.res = Integer.parseInt(temp); 074. 075.g = new Grafo(res); 076. 077.for (int i = 0; i < res; i++) { 078.System.out.println("Cual es el nombre del nodo [" + (i + 1) 079.+ "]:\n"); 080.temp = br.readLine(); 081.g.ingresarNombre(i, temp.charAt(0)); 082.} 083.for (int i = 0; i < res; i++) { 084.for (int j = 0; j < res; j++) { 085.if (i < j) { 086.System.out.println("El nodo " + g.getNombre(i) 087.+ " esta conectado con el nodo " + g.getNombre(j) 088.+ " (s/n)\n"); 089.temp = br.readLine(); 090.if (temp.charAt(0) == 's') { 091.int peso; 092.System.out.println("Cual es el peso del arco:\n"); 093.temp = br.readLine(); 094.peso = Integer.parseInt(temp); 095.g.ingresarArco(i, j, peso); 096.} else { 097.g.ingresarArco(i, j, 10000); 098.} 099.} 100.} 101.} 102. 103.g.calcular(); 104.for (int i = 0; i < res; i++) { 105.for (int j = 0; j < res; j++) { 106.if (i > j) { 107.System.out.println("El camino mas corto entre los nodos:" 108.+ g.getNombre(i) + "-" + g.getNombre(j) + " es: \n" 109.+ g.caminocorto(i, j) + " y su peso es: " 110.+ g.pesominimo(i, j)); 111.} 112.} 113.} 114.} 115.}
Como sabemos, en el computador no se puede representar el infinito, por lo tanto, cuando no exista conexin entre dos nodos, inicialic ese peso con 100000, sabiendo que ste no es nmero tan grande si es que queremos representar pesos elevados, pero como el desarrollo de esta aplicacin fue pensada con fines pedaggicos y no profesionales, en ese caso no importaba mucho.