martes, 16 de abril de 2013

ESTADO DEL ARTE


El algoritmo de Floyd es muy similar al Warshall, pero trabaja con grafos ponderados. Es decir, el valor de la “flecha” que representamos en la matriz puede ser cualquier entero que se nos ocurra, o infinito. Infinito marca que no existe unión entre los nodos. Esta vez, el resultado será una matriz donde estarán representadas las distancias mínimas entre nodos, seleccionando los caminos más convenientes según su ponderación (“peso”). Por ejemplo, si de “A” a “B” hay 36 (km), pero de “A” a “C” hay 2(km) y de “C” a “B” hay 10 (km), el algoritmo nos devolverá finalmente que de “A” a “C” hay 12 (km).



El algoritmo de Warshall es un ejemplo de algoritmo booleano. A partir de una tabla inicial compuesta de 0`s (no hay correspondencia inicial en el grafo) y 1`s (hay una correspondencia, llamase “flecha”, entre nodos), obtiene una nueva matriz denominada “Matriz de Clausura Transitiva” en la que se muestran todas las posibles uniones entre nodos, directa o indirectamente. Es decir, si de “A” a “B” no hay una “flecha”, es posible que si haya de “A” a “C” y luego de “C” a “B”. Luego, este resultado se verá volcado en la matriz final.



El algoritmo de Floyd-Warshall es un algoritmo de análisis de grafos para que, de forma eficiente y simultánea, encuentre los caminos más cortos dentro de un grafo en el cual las aristas tengan un costo (distancia entre nodo y nodo, duración del viaje entre nodos, etc.). Al ejecutar el algoritmo encontrara el camino menor o más corto de entre todos los pares de vértices, pero no devuelve los detalles de los caminos en sí. El algoritmo es un ejemplo de la Programación Dinámica y su variación más conocida fue publicada en 1962 por Robert Floyd. Aunque es necesario comentar también 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 múltiples pseudónimos: Algoritmo de Floyd, Algoritmo de Roy-Floyd, Algoritmo de Roy-Warshall, Algoritmo WFI.

BIOGRAFIA DE SUS CREADORES


Bernard Roy (nacida en 1934), es profesor emérito de la Universidad Paris-Dauphine.  En 1974 se fundó el "Laboratoire d'Analyse et de modelización des Systèmes pour l'aide à la Decisión" (LAMSADE). Ha trabajado en la teoría de grafos y el análisis de decisión multicriterio (MCDA), habiendo creado el ELECTRE familia de métodos. El nombre ELECTRE significa "Eliminación Et Choix Traduisant la Réalité".

Robert W. Floyd (8 de junio de 1936 - 25 de septiembre de 2001) fue un prominente científico estadounidense en informática.

Nacido en Nueva York, Floyd culminó el bachillerato a los 14 años. Se graduó en la Universidad de Chicago en 1953 a los 17 años y como Físico en 1958.

Operador de computadoras en los años 60, publicó sus primeros artículos los cuales fueron de gran influencia y fue nombrado profesor asociado en la Universidad de Carnegie Mellon. Seis años más tarde fue nombrado profesor en la Universidad de Stanford.

Entre sus contribuciones se encuentran el diseño y análisis de algoritmos eficientes para encontrar el camino más corto en un grafo y para el problema de reconocimiento de frases, pero probablemente su logro más importante fue el ser pionero, con su artículo de 1967 «Assigning Meanings to Programs», en el área de verificación de programas utilizando aserciones lógicas, donde aparece la importante noción de invariante, esencial para demostrar propiedades de programas iterativos.

Floyd recibió el Premio Turing de la ACM en 1978 «por tener una clara influencia en las metodologías para la creación de software eficiente y confiable, y por haber contribuido a la fundación de las subáreas teoría del reconocimiento de frases, semántica de los lenguajes de programación, verificación automatizada de programas, síntesis automatizada de programas y análisis de algoritmos».


Stephen Warshall (15 noviembre 1935 a 11 diciembre 2006) nació en New York City. Durante su carrera, Warshall llevado a cabo la investigación y el desarrollo de sistemas operativos, diseño, diseño del compilador del lenguaje, y la investigación operativa. Warshall murió el 11 de diciembre de 2006 de cáncer en su casa de Gloucester, Massachusetts. Le sobreviven su esposa, Sarah Dunlap, y dos hijos, Andrew D. Warshall y Santa VZ Warshall.


Educación


Warshall fue a la escuela pública en Brooklyn. Se graduó de A.B. Davis High School en Mount Vernon, Nueva York y asistió a la Universidad de Harvard, recibiendo una licenciatura en matemáticas en 1956. Nunca recibió un grado avanzado ya que en ese momento no estaban disponibles en los programas de sus áreas de interés. Sin embargo, tomó cursos de postgrado en varias universidades y ha contribuido al desarrollo de la informática y la ingeniería de software. En el año académico 1971-1972, fue profesor en la ingeniería de software en las universidades francesas.


Algoritmo Warshall


Hay una anécdota interesante de su prueba de que el algoritmo de clausura transitiva, ahora conocido como algoritmo de Warshall, es correcto. Él y un colega de Operaciones Técnicas apuesto una botella de ron en el primero que podría determinar si este algoritmo siempre funciona. Warshall se acercó con su prueba durante la noche, ganando la apuesta y el ron, el cual compartió con el perdedor de la apuesta. Porque Warshall no le gustaba sentarse en un escritorio, hizo gran parte de su trabajo creativo en lugares no convencionales, como en un velero en el Océano Índico o en un huerto de limón griego.

EXPLICACION DEL ALGORITMO


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 óptimo.
Considerar un grafo G con nodos o vértices V, cada una numerada de 1 a N, ad más de una función que al ingresar i, j, k devuelve el camino más corto entre i y j pasando solo por el conjunto {1, 2,…, k}. Ahora, utilizando esta función, el objetivo es encontrar el camino más corto entre i para cada j usando solo los vértices 1 hasta k+1.
Existen dos candidatos para cada uno de esos caminos: o el verdadero camino más corto pasando por los nodos {1,…, k}; o existe un camino que vaya desde i hasta k+1, después 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 función anterior, y está claro que si existiera un camino desde i hasta k+1 hasta j, entonces el valor de este camino seria la concatenación de el camino más corto de i hasta k+1 (usando vértices {1,…, k}) y el camino más corto desde k+1 hasta j (también usando vértices {1,…, k}).
Si v(i,j) es el valor o costo de la arista entre los nodos i y j, podemos definir la función ahora llamada camino Corto(i,j,k) en los términos de la siguiente formula recursiva: el caso base seria
 
camino Corto(i,j,0) = v(i,j)
y el caso recursivo seria
camino Corto(i,j,k)= min(camino Corto(i,j,k-1), camino Corto(i ,k,k-1)+ camino Corto(k,j,k-1)
Esta fórmula es el corazón del algoritmo de Floyd-Warshall. El algoritmo funciona primero calculando la función para todos los pares (i,j) para k=1, después k=2, etc. Este proceso continua hasta k=n; y hemos encontrado el camino más corto para todos los pares (i, j) usando cualquier nodo intermedio.


ALGORITMO


package javaapplication16;

import java.util.Scanner;

/**
 *
 * @author Denis,Lewis,Johna
 */
public class JavaApplication16 {

    public static int[][] shortestpath(int[][] adj, int[][] path) {

        int n = adj.length;
        int[][] ans = new int[n][n];

        // Implementar el algoritmo en una matriz de copia de modo que la adyacencia no es
        //destruido.
        copy(ans, adj);

        // Calcular rutas sucesivamente a través de una mejor k vértices.
        for (int k = 0; k < n; k++) {

            // Es así que entre cada par de puntos posibles.
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {


                    if (ans[i][k] + ans[k][j] < ans[i][j]) {
                        ans[i][j] = ans[i][k] + ans[k][j];
                        path[i][j] = path[k][j];
                    }
                }
            }
        }

        // Devuelva la matriz camino más corto.
        return ans;
    }

    //Copia el contenido del array b en un array. Se asume que tanto a como
    //B es una matriz 2D de dimensiones idénticas.
    public static void copy(int[][] a, int[][] b) {

        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a[0].length; j++) {
                a[i][j] = b[i][j];
            }
        }
    }

    // Devuelve el menor de a y b.
    public static int min(int a, int b) {
        if (a < b) {
            return a;
        } else {
            return b;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Scanner stdin = new Scanner(System.in);

        // Pruebas fuera con algoritmo gráfico mostrado en clase.
        int[][] m = new int[5][5];
        m[0][0] = 0;
        m[0][1] = 3;
        m[0][2] = 8;
        m[0][3] = 10000;
        m[0][4] = -4;
        m[1][0] = 10000;
        m[1][1] = 0;
        m[1][2] = 10000;
        m[1][3] = 1;
        m[1][4] = 7;
        m[2][0] = 10000;
        m[2][1] = 4;
        m[2][2] = 0;
        m[2][3] = 10000;
        m[2][4] = 10000;
        m[3][0] = 2;
        m[3][1] = 10000;
        m[3][2] = -5;
        m[3][3] = 0;
        m[3][4] = 10000;
        m[4][0] = 10000;
        m[4][1] = 10000;
        m[4][2] = 10000;
        m[4][3] = 6;
        m[4][4] = 0;

        int[][] shortpath;
        int[][] path = new int[5][5];

        // Inicializar con el vértice anterior para cada borde. -1 indica
        // no tal vertice.
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                if (m[i][j] == 10000) {
                    path[i][j] = -1;
                } else {
                    path[i][j] = i;
                }
            }
        }

        // Esto significa que no tiene que ir a ninguna parte para ir de i a i.
        for (int i = 0; i < 5; i++) {
            path[i][i] = i;
        }

        shortpath = shortestpath(m, path);

        // Imprime distancias más cortas.
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                System.out.print(shortpath[i][j] + " ");
            }
            System.out.println();
        }

        System.out.println("De dónde a dónde usted quiere encontrar el camino más corto?(0 to 4)");
        int start = stdin.nextInt();
        int end = stdin.nextInt();

        // La ruta finalizará siempre en fin.
        String myPath = end + "";

        // Recorrer cada vértice anterior hasta que vuelvas a empezar.
        while (path[start][end] != start) {
            myPath = path[start][end] + " -> " + myPath;
            end = path[start][end];
        }

        // Sólo tiene que añadir comienzo de nuestra cadena y de impresión.
        myPath = start + " -> " + myPath;
        System.out.println("Este es el camino " + myPath);
        // TODO code application logic here
    }
}

PARA QUE SE USA

El algoritmo de Floyd-Warshall puede ser usado para resolver los siguientes problemas, entre otros.
• Caminos corto en un grafo dirigido (Algoritmo de Floyd)
• Clausura transitiva de grafos dirigidos (Algoritmo de Warshall). En el algoritmo original de Warshal l, el grafo no tiene aristas con coste o valor y es representado por una matriz Booleana de proximidad. Entonces la operación de suma es remplazada por la aritmética Booleana “AND” y la operación de mínimo es remplazada por “OR”.
Búsqueda de expresiones regulares dependiendo del lenguaje regular aceptado por una autómata finito (Algoritmo de Kleene)
Inversión de matrices de números reales (Algoritmo de Gauss-Jordán)
• Planeamiento
óptimo de rutas. En esta aplicación uno está interesado en encontrar la ruta con el máximo tráfico entre dos vértices. Esto significa que, en vez de tomar el mínimo, en su lugar uno toma el máximo. El coste de arista representa la constante de flujo. Los costes de caminos representan cuellos de botella; así que la operación de adición es reemplazada por la operación de mínimo.
• Probar si un grafo indirecto es bipartito (Un Grafo bipartito se denomina en Teoría de grafos a un grafo cuyos vértices se pueden separar en dos conjuntos disjuntos V1 y V2 y las aristas siempre unen vértices de un conjunto con vértices de otro).
• Calculo rápido de redes de organización de datos.
• Caminos de máximo ancho de banda.

lunes, 15 de abril de 2013

EJEMPLO DE IMPLEMENTACIÓN DEL ALGORITMO


Hallar el camino mínimo desde el vértice 3 hasta 4 en el grafo con la siguiente matriz de distancias:


Aplicamos el algoritmo de Floyd-Warshall, y para ello en cada iteración fijamos un vértice intermedio.

1ª Iteración: nodo intermedio = 1
La matriz es simétrica, por lo que solamente hará falta calcular el triángulo superior de las distancias.
d23 = min(d23, d21 + d13) = 8
d24 = min(d24, d21 + d14) = 4
d25 = min(d25, d21 + d15) = 9
d26 = min(d26, d21 + d16) = Descripción: \infty
d32 = min(d32, d31 + d12) = 8
d34 = min(d34, d31 + d14) = 6
d35 = min(d35, d31 + d15) = 7
d36 = min(d36, d31 + d16) = 1
d45 = min(d45, d41 + d15) = Descripción: \infty
d46 = min(d46, d41 + d16) = 4
d56 = min(d56, d51 + d16) = Descripción: \infty
La matriz de distancia después de esta iteración es:



2ª Iteración: nodo intermedio = 2
d13 = min(d13, d12 + d23) = 5
d14 = min(d14, d12 + d24) = 1
d15 = min(d15, d12 + d25) = 12
d16 = min(d16, d12 + d26) = Descripción: \infty
d34 = min(d34, d32 + d24) = 6
d35 = min(d35, d32 + d25) = 7
d36 = min(d36, d32 + d26) = 1
d45 = min(d45, d42 + d25) = 13
d46 = min(d46, d42 + d26) = 4
d56 = min(d56, d52 + d26) = Descripción: \infty
La matriz de distancia después de esta iteración es:

3ª Iteración: nodo intermedio = 3
d12 = min(d12, d13 + d32) = 3
d14 = min(d14, d13 + d34) = 1
d15 = min(d15, d13 + d35) = 12
d16 = min(d16, d13 + d36) = 6
d24 = min(d24, d23 + d34) = 4
d25 = min(d25, d23 + d35) = 9
d26 = min(d26, d23 + d36) = 9
d45 = min(d45, d43 + d35) = 13
d46 = min(d46, d43 + d36) = 4
d56 = min(d56, d53 + d36) = 8
La matriz de distancia después de esta iteración es:

4ª Iteración: nodo intermedio = 4
d12 = min(d12, d14 + d42) = 3
d13 = min(d13, d14 + d43) = 5
d15 = min(d15, d14 + d45) = 12
d16 = min(d16, d14 + d46) = 5
d23 = min(d23, d24 + d43) = 8
d25 = min(d25, d24 + d45) = 9
d26 = min(d26, d24 + d46) = 8
d35 = min(d35, d34 + d45) = 7
d36 = min(d36, d34 + d46) = 1
d56 = min(d56, d54 + d46) = 8
La matriz de distancia después de esta iteración es:

5ª Iteración: nodo intermedio = 5
d12 = min(d12, d15 + d52) = 3
d13 = min(d13, d15 + d53) = 5
d14 = min(d14, d15 + d54) = 1
d16 = min(d16, d15 + d56) = 5
d23 = min(d23, d25 + d53) = 8
d24 = min(d24, d25 + d54) = 4
d26 = min(d26, d25 + d56) = 8
d34 = min(d34, d35 + d54) = 6
d36 = min(d36, d35 + d56) = 1
d46 = min(d46, d45 + d56) = 4
La matriz de distancia después de esta iteración es:

6ª Iteración: nodo intermedio = 6
d12 = min(d12, d16 + d62) = 3
d13 = min(d13, d16 + d63) = 5
d14 = min(d14, d16 + d64) = 1
d15 = min(d15, d16 + d65) = 12
d23 = min(d23, d26 + d63) = 8
d24 = min(d24, d26 + d64) = 4
d25 = min(d25, d26 + d65) = 9
d34 = min(d34, d36 + d64) = 5
d35 = min(d35, d36 + d65) = 7
d45 = min(d45, d46 + d65) = 12
La matriz de distancia después de esta iteración es:
Ya se han hecho todas las iteraciones posibles. Por tanto, el camino mínimo entre 2 vértices cualesquiera del grafo será el obtenido en la matriz final. En este caso, el camino mínimo entre 3 y 4 vale 5.


IMPLEMENTACION DEL ALGORITMO


package javaapplication15;

import javax.swing.JOptionPane;

/**
 *
 * @author Denis,lewis,johana
 */
public class JavaApplication15 {

    private int n;
    private int[][] A = new int[10][10];
    private int[] vect1 = new int[10];
    private int[] vect2 = new int[10];
    private int[][] B = new int[10][10];

    public void ingresar() {
        setN(Integer.parseInt(JOptionPane.showInputDialog(null, "Ingrese numero de nodos")));
        int i, j;
        for (i = 1; i <= getN(); i++) {
            for (j = 1; j <= getN(); j++) {
                getA()[i][j] = Integer.parseInt(JOptionPane.showInputDialog(null, "Ingrese la Matriz" + getA()[i][j]));
            }
        }
    }

    public void nodointer() {
        int i, j;
        for (i = 1; i <= 6; i++) {
            for (j = 1; j <= 6; j++) {
                if (i == j) {
                    getB()[i][j] = 0;
                } else {
                    getB()[i][j] = j;
                }
            }
        }
    }

    public void floid() {
        int bucle, i, j, suma;
        for (bucle = 1; bucle <= getN(); bucle++) {
            for (i = 1; i <= getN(); i++) {
                getVect1()[i] = getA()[bucle][i];
                getVect2()[i] = getA()[i][bucle];
            }
            for (i = 1; i <= getN(); i++) {
                for (j = 1; j <= getN(); j++) {
                    if (getVect2()[i] == 999 || getVect1()[j] == 999) {
                        suma = 999;
                    } else {
                        suma = getVect2()[i] + getVect1()[j];
                    }
                    if (suma < getA()[i][j]) {
                        getA()[i][j] = suma;
                        getB()[i][j] = bucle;
                    }
                }
            }
        }
    }

    public void mostrar1() {
        int i, j;
        JOptionPane.showInputDialog(null, "Imprime distancias o pesos optimo");
        for (i = 1; i <= getN(); i++) {
            for (j = 1; j <= getN(); j++) {
                JOptionPane.showMessageDialog(null, "Distancia es: " + getA()[i][j]);
            }
            JOptionPane.showMessageDialog(null, "\n\n");
        }
    }

    public void mostrar2() {
        int i, j;
        JOptionPane.showInputDialog(null, "Imprime matriz intermedios");
        for (i = 1; i <= getN(); i++) {
            for (j = 1; j <= getN(); j++) {
                JOptionPane.showMessageDialog(null, "Intermedios es:" + getB()[i][j]);
            }
            JOptionPane.showMessageDialog(null, "\n\n");
        }
    }

    public void preguntar() {
        int i, j;
        i = Integer.parseInt(JOptionPane.showInputDialog(null, "De que vertice a que vertice desea ir a: "));
        j = Integer.parseInt(JOptionPane.showInputDialog(null, "De que vertice a que vertice desea ir b: "));
        if (i == 0 || j == 0 || i == j) {
            JOptionPane.showMessageDialog(null, "Distancia minima es 0");
        } else {
            JOptionPane.showMessageDialog(null, "Distancia minima" + getA()[i][j] + "\n");
            JOptionPane.showMessageDialog(null, "Pasa por el: \t" + getB()[i][j] + "\t Y despues por el: \t" + j);
        }
    }

    public static void main(String[] args) {
        JavaApplication15 j = new JavaApplication15();
        j.ingresar();
        j.nodointer();
        j.floid();
        j.mostrar1();
        j.mostrar2();
        j.preguntar();

    }

    /**
     * @return the n
     */
    public int getN() {
        return n;
    }

    /**
     * @param n the n to set
     */
    public void setN(int n) {
        this.n = n;
    }

    /**
     * @return the A
     */
    public int[][] getA() {
        return A;
    }

    /**
     * @param A the A to set
     */
    public void setA(int[][] A) {
        this.A = A;
    }

    /**
     * @return the vect1
     */
    public int[] getVect1() {
        return vect1;
    }

    /**
     * @param vect1 the vect1 to set
     */
    public void setVect1(int[] vect1) {
        this.vect1 = vect1;
    }

    /**
     * @return the vect2
     */
    public int[] getVect2() {
        return vect2;
    }

    /**
     * @param vect2 the vect2 to set
     */
    public void setVect2(int[] vect2) {
        this.vect2 = vect2;
    }

    /**
     * @return the B
     */
    public int[][] getB() {
        return B;
    }

    /**
     * @param B the B to set
     */
    public void setB(int[][] B) {
        this.B = B;
    }
}