Descarga la aplicación para disfrutar aún más
Vista previa del material en texto
UPN, PASIÓN POR TRANSFORMAR VIDAS SESIÓN 14: Teoría de grafos Ing. Mitchell Blancas ANALISIS DE ALGORITMOS Y ESTRATEGIAS DE PROGRAMACION LOGRO DE LA SESIÓN Al término de la sesión el estudiante aplica algoritmos sobre grafos en la solución de problemas propuestos y los representa a través de algoritmos. ¡Pregunta! ¿Qué algoritmos sobre grafos utilizamos a diario? Algoritmo de Dijsktra Sirve para encontrar el camino más corto de un vértice elegido a cualquier otro vértice del grafo. 0 Lima 2 Tacna 1 Ica 3 Ilo 4 Cuzco 12 10 8 8 15 20 El algoritmo de Dijsktra encontrará todas las distancias mínimas para ir de un vértice de origen (Lima) a todos los otros vértices (otras ciudades), por ejemplo si la ciudad origen es Lima, se obtendrá: Lima – Ica = 10 Km Lima – Tacna = 23 Km Lima – Ilo = 15 Km Lima – Cuzco = 12 Km GRAFOS Un grafo es una estructura de datos dinámica no lineal que representa objetos y las relaciones entre ellos. Por ej., pueden modelar redes de computadoras, redes de tránsito, ciudades y las distancias entre ellas, etc. Objetos: Nodos o vértices -> V= {a, b, c, d} Relaciones: Aristas -> A = {(a, b), (b, c), (b, d), (c, d)} a b c d GRAFOS: EJEMPLOS Representa gráficamente los siguientes grafos: Grafo 1: V= {w, x, y, z} A = {(w, y), (w, z), (x, z), (y, z)} Grafo 2: V= {10, 20, 30, 40, 50} A = {(10, 40), (10, 50), (20, 30), (20, 40), (30, 50), (40, 50)} GRAFOS: TIPOS Grafo dirigido (Dígrafo) Sus aristas siguen una secuencia, indican que una relación entre 2 nodos que no es recíproca. Grafo no dirigido Sus aristas no están ordenadas, indican que una relación entre 2 nodos es recíproca. a b c d a b c d GRAFOS: TERMINOLOGÍA BÁSICA Nodos adyacentes a un nodo v (vecinos): Todos los nodos unidos a v a través de una arista. Longitud de un camino: Número de aristas entre un nodo v y un nodo w. Ciclo: Cualquier camino en el que el primer y último nodo son iguales. Conectividad: Se dice que dos nodos están conectados si existe un camino entre ellos. a b e d c f GRAFOS: TERMINOLOGÍA BÁSICA Subgrafo: Dado un grafo, un subgrafo es un subconjunto de nodos y aristas tal que forman otro grafo más pequeño. Grafo conexo: Un grafo no dirigido es conexo si hay un camino entre cualquier par de nodos. conexas: subgrafos Dado un disjuntos grafo no que son Componentes dirigido, son conexos. Grafo etiquetado: Es aquel grafo en la que sus aristas tienen un valor asociado. a b e d c f a b e d c f 10 50 0 30 20 30 GRAFOS: TERMINOLOGÍA BÁSICA Grado de un nodo: Cantidad de aristas que inciden en él. En grafos dirigidos: Grado de entrada Grado de salida. a b e d c f a b c d f e GRAFOS: MATRICES DE ADYACENCIA Una matriz de adyacencia es una matriz de tamaño nxn, donde n es la cantidad de nodos o vértices del grafo. Cada entrada de la matriz tiene valores de 0 o 1 dependiendo de si existe o no una arista entre dos nodos. a b c d e Para grafos no dirigidos, la matriz de adyacencia resulta ser simétrica. M a b c d e a 0 1 1 0 0 b 1 0 0 0 1 c 1 0 0 1 0 d 0 0 1 0 1 e 0 1 0 1 0 GRAFOS: MATRICES DE COSTOS Una matriz de costos es una matriz de tamaño nxn, donde n es la cantidad de nodos o vértices de un grafo etiquetado. Cada entrada de la matriz tiene el costo o peso de la arista que existe entre dos nodos. a b e d c M a b c d e a 0 50 10 ∞ ∞ b ∞ 0 ∞ ∞ ∞ c ∞ ∞ 0 ∞ ∞ d ∞ ∞ 25 0 40 e ∞ 20 ∞ ∞ 0 50 10 20 40 25 GRAFOS: MATRICES DE ADYACENCIA Ventajas Es una forma de representación bastante sencilla. Permiten verificar rápidamente si existe o no una arista entre dos nodos. Desventajas El número de nodos del grafo no puede variar una vez iniciado el programa. Si el grafo posee muchos nodos y pocas aristas (a<<n2) se desperdicia mucha memoria. GRAFOS: LISTAS DE ADYACENCIA Una lista de adyacencia consta de un arreglo o lista de nodos, en la que cada uno de ellos apunta a una lista de los nodos con los cuales tiene adyacencia. a b e d c a b c d e NULL b c NULL NULL NULL c e NULL b NULL GRAFOS: LISTAS DE ADYACENCIA Una lista de adyacencia consta de un arreglo o lista de nodos, en la que cada uno de ellos apunta a una lista de los nodos con los cuales tiene adyacencia. a b e d c a b c d e NULL NULL NULL NULL NULL NULL GRAFOS: LISTAS DE ADYACENCIA PARA GRAFO ETIQUETADO Similar a una lista de adyacencia normal. Sin embargo, en cada adyacencia se almacenan también los pesos de cada arista. a b e d c a b c d e NULL b NULL NULL NULL NULL NULL 50 10 20 40 25 50 c 10 c 25 e 40 b 20 GRAFOS: LISTAS DE ADYACENCIA Ventajas Mucho más adecuada cuando a<<n2. Desventajas Es una forma de representación más compleja. Es ineficiente cuando se desea encontrar las aristas que llegan a un nodo. OPERACIONES CON GRAFOS DIRIGIDOS Las operaciones que se pueden hacer con Grafos son: Inicialización de un Grafo Inserción de un Nodo Inserción de una Arista Eliminación de una Arista Eliminación de un Nodo Recorrido en Anchura Recorrido en Profundidad GRAFOS DIRIGIDOS: DEFINICIÓN DE UN NODO Un nodo se define de la siguiente manera: class Nodo { public int dato; public Nodo sgte; public Arista ady; } D1 Adyacencias Siguiente nodo GRAFOS DIRIGIDOS: DEFINICIÓN DE UNA ARISTA Una arista se define de la siguiente manera: class Arista { public Nodo destino; public Arista sgte; } Siguiente arista Nodo destino INICIALIZACIÓN DE UN GRAFO DIRIGIDO Consiste en crear un grafo vacío. Grafo NULL public Grafo() { inicio = null; } Grafo grafo = new Grafo(); INSERCIÓN DE UN NODO EN UN GRAFO DIRIGIDO Consta de los siguientes pasos: Crear el nodo y asignarle el dato que queremos insertar al grafo. El nuevo nodo apunta hacia adelante a NULL y no tiene adyacencias. Verificar si el grafo está vacío Si lo está, el grafo se convierte en el nuevo nodo. En caso contrario, agregar el nodo al final del grafo. INSERCIÓN DE UN NODO EN UN GRAFO DIRIGIDO NULL Grafo 1 Nuevo Nodo 2.1 A NULL NULL Grafo A NULL NULL A Grafo A Agregar INSERCIÓN DE UN NODO EN UN GRAFO DIRIGIDO B Grafo Grafo A NULL NULL B C C NULL A NULL 1 Nuevo Nodo D NULL NULL A B C D Agregar INSERCIÓN DE UN NODO EN UN GRAFO DIRIGIDO Grafo A NULL B C C NULL A NULL D NULL B NULL 2.2 Grafo A B C D D Agregar INSERCIÓN DE UN NODO EN UN GRAFO DIRIGIDO public void insertarNodo(int valor) { Nodo nuevoNodo, nodoUltimo; nuevoNodo = new Nodo(); nuevoNodo.dato = valor; nuevoNodo.sgte = null; nuevoNodo.ady = null; if (inicio == null) inicio = nuevoNodo; else{ nodoUltimo = inicio; while (nodoUltimo.sgte != null) nodoUltimo = nodoUltimo.sgte; nodoUltimo.sgte = nuevoNodo; } } 1 2 2.2 2.1 INSERCIÓN DE UNA ARISTA A UN GRAFO DIRIGIDO Consta de los siguientes pasos: Obtener el nodo origen de la arista. Obtener el nodo destino de la arista. Crear la arista. La nueva arista apunta hacia adelante a NULL y su nodo destino es el que se obtuvo en el paso 2. Agregar la arista al final de la lista de adyacencias del nodo origen. INSERCIÓN DE UNA ARISTA A UN GRAFO DIRIGIDO D, A Agregar Grafo A B C D Grafo A NULL B C C NULL A NULL D NULL B NULL INSERCIÓN DE UNA ARISTA A UN GRAFO DIRIGIDO Grafo A NULL B C C NULL A NULL D NULL B NULL Grafo A NULL B C C NULL A NULL D NULL B NULL 1 2 D, A Agregar INSERCIÓN DE UNA ARISTA A UN GRAFO DIRIGIDO 3 NULL A Grafo A NULL B C C NULL A NULL D B NULL D, A Agregar A NULL 4 Grafo A B C D INSERCIÓNDE UNA ARISTA A UN GRAFO DIRIGIDO public void insertarArista(int origen, int destino) { Arista nuevaArista, ultimaArista; Nodo nodoOrigen, nodoDestino; nodoOrigen = obtenerNodo(origen); nodoDestino = obtenerNodo(destino); nuevaArista = new Arista(); nuevaArista.destino = nodoDestino; nuevaArista.sgte = null; if (nodoOrigen.ady == null){ nodoOrigen.ady = nuevaArista; } else{ ultimaArista = nodoOrigen.ady; while (ultimaArista.sgte != null) ultimaArista = ultimaArista.sgte; ultimaArista.sgte = nuevaArista; } } 2 1 3 4 ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO Consta de los siguientes pasos: Obtener el nodo origen de la arista. Obtener la lista de adyacencias del nodo origen. Con base en el nodo destino, eliminar la arista tal como se hace en cualquier lista enlazada simple. ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO B, A Eliminar A B C D Grafo A NULL B C C NULL A NULL D B NULL A NULL Grafo D ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO B, A Eliminar Grafo A NULL B C C NULL A NULL D B NULL A NULL D 1 A NULL B C C NULL A NULL D B NULL A NULL D 2 Grafo ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO B, A Eliminar A NULL B C NULL A D 3 Grafo … A NULL B C NULL A D Grafo … A NULL B C NULL D Grafo … ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO B, A Eliminar A NULL B C C NULL D NULL D B NULL A NULL Grafo A B C D Grafo A B C D Grafo ELIMINACIÓN DE UNA ARISTA DE UN GRAFO DIRIGIDO public void eliminarArista(int origen, int destino) { Nodo nodoOrigen; Arista aristaAnterior = null, aristaActual; nodoOrigen = obtenerNodo(origen); aristaActual = nodoOrigen.ady; while (aristaActual != null && aristaActual.destino.dato != destino){ aristaAnterior = aristaActual; aristaActual = aristaActual.sgte; } if (aristaAnterior == null){ nodoOrigen.ady = nodoOrigen.ady.sgte; } else{ aristaAnterior.sgte = aristaActual.sgte; } aristaActual = null; } 2 1 3 ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO Consta de los siguientes pasos: Obtener el nodo que se desea eliminar. Eliminar todas las aristas cuyo destino es el nodo a eliminar. Eliminar todas las adyacencias del nodo a eliminar. Eliminar el nodo tal como se eliminaría de cualquier lista enlazada. ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO A Eliminar A B C D Grafo A NULL B C C NULL A NULL D B NULL A NULL Grafo D ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO A Eliminar Grafo A NULL B C C NULL A NULL D B NULL A NULL D 1 2 Grafo A NULL B C C NULL A NULL D B NULL A NULL D ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO A Eliminar 3 Grafo A NULL B C C NULL NULL D B NULL NULL D 4 Grafo A NULL B C NULL NULL D B NULL NULL D ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO A Eliminar Grafo B C NULL NULL D B NULL NULL D ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO A B C D Grafo A B C D Grafo A B C D Grafo B C D Grafo ELIMINACIÓN DE UN NODO DE UN GRAFO DIRIGIDO public void eliminarNodo(int valor){ Nodo nodoAnterior = null, nodoActual, nodoOrigen = inicio; Arista adyacencias, aux; while (nodoOrigen != null && nodoOrigen.dato != valor){ nodoAnterior = nodoOrigen; nodoOrigen = nodoOrigen.sgte; } nodoActual = inicio; while (nodoActual != null){ eliminarArista(nodoActual.dato, valor); nodoActual = nodoActual.sgte; } adyacencias = nodoOrigen.ady; while (adyacencias != null){ aux = adyacencias; adyacencias = adyacencias.sgte; aux = null; } if (nodoAnterior == null) inicio = inicio.sgte; else nodoAnterior.sgte = nodoOrigen.sgte; nodoOrigen = null; } 2 1 3 4 RECORRIDO EN ANCHURA El recorrido en anchura (BFS), comienza eligiendo una raíz (nodo inicial) y se exploran todas sus adyacencias. Luego, por cada nodo adyacente, se exploran sus respectivos vecinos, hasta que finalice el recorrido. Nodo inicial A: A - B - C - D - E Nodo inicial B: B - D - E Nodo inicial F: F A D C B E F RECORRIDO EN ANCHURA Hace uso de una cola de nodos. Cada nodo tiene un estado: No visitado (N) y Visitado (V). Consta de los siguientes pasos: Marcar todos los nodos como no visitados. Encolar el nodo raíz y marcarlo como visitado. Mientras que la cola no esté vacía. Desencolar el nodo del frente de la cola y mostrar elemento Obtener las adyacencias del nodo que se acaba de desencolar. Por cada nodo adyacente, si no ha sido visitado, marcar como visitado y encolarlo. RECORRIDO EN ANCHURA A D C B E F N N N N N N N Raíz 1 Salida: RECORRIDO EN ANCHURA A D C B E A Frente Fin NULL N V N N N N F N Raíz 2 Salida: RECORRIDO EN ANCHURA A D C B E Frente Fin NULL N V N N N N F N Raíz 3.1 A Salida: A RECORRIDO EN ANCHURA A D E F Frente Fin NULL N V N B N C N N N Raíz 3.2 Salida: A RECORRIDO EN ANCHURA B A D C B E Frente N V V V N N F N Raíz 3.3 Frente Fin C NULL Salida: A RECORRIDO EN ANCHURA A D C B E Frente Fin N V V V N N F N Raíz 3.1 C Frente Fin NULL B Salida: A - B RECORRIDO EN ANCHURA A C B E Frente Fin N V V V N D N F N Raíz 3.2 C Frente Fin NULL Salida: A - B RECORRIDO EN ANCHURA A D C B E N V V V V N F N Raíz 3.3 C Frente Fin Frente Fin D NULL Salida: A - B RECORRIDO EN ANCHURA A D C B E N V V V V N F N Raíz 3.1 D Frente Fin NULL C Salida: A - B - C RECORRIDO EN ANCHURA A C B E N V V V V D N F N Raíz 3.2 D Frente Fin NULL Salida: A - B - C RECORRIDO EN ANCHURA A D C B E N V V V V N F N Raíz 3.1 Frente Fin NULL D Salida: A - B - C - D RECORRIDO EN ANCHURA A D C B N V V V V N F N E Raíz 3.2 Frente Fin NULL Salida: A - B - C - D RECORRIDO EN ANCHURA A D C B E N V V V V N F V Raíz 3.3 E Frente Fin NULL Salida: A - B - C - D RECORRIDO EN ANCHURA A D C B E N V V V V N F V Raíz 3.1 Frente Fin NULL E Salida: A - B - C - D - E RECORRIDO EN ANCHURA public void recorridoAnchura(int origen){ … inicializarNodos(); nodoOrigen = obtenerNodo(origen); nodoOrigen.estado = 'V'; cola.enqueue(nodoOrigen.dato); while (cola.getFrente() != null){ valor = cola.dequeue(); Console.Write(valor + " "); adyacencias = obtenerNodo(valor).ady; while (adyacencias != null) { nodoDestino = adyacencias.destino; if (nodoDestino.estado == 'N') { nodoDestino.estado = 'V'; cola.enqueue(nodoDestino.dato); } adyacencias = adyacencias.sgte; } } } 2 1 3.1 3.2 3 3.3 RECORRIDO EN PROFUNDIDAD El recorrido en profundidad (DFS), comienza eligiendo un nodo y explora toda su descendencia hasta que no se pueda continuar. Luego, se retrocede y se repite el proceso con los nodos restantes hasta que el grafo haya sido recorrido completamente. A D C B E F Nodo inicial A: A - B - D - E - C - F Nodo inicial B: B - D - E - A - C - F Nodo inicial F: F - A - B - D - E - C RECORRIDO EN PROFUNDIDAD Hace uso de dos funciones donde una de ellas es recursiva. Cada nodo tiene un estado: No visitado (N) y Visitado (V). FUNCIÓN PRINCIPAL Consta de los siguientes pasos: Marcar todos los nodos como no visitados. Para cada nodo del grafo, si no está visitado, visitarlo. FUNCIÓN VISITAR Consta de los siguientes pasos: Marcar el nodo como visitado y mostrar elemento. Obtener las adyacencias del nodo que se desea visitar. Por cada nodo adyacente, si no fue visitado, visitarlo.RECORRIDO EN PROFUNDIDAD A D C B E F N N N N N N N Raíz P.1 Salida: RECORRIDO EN PROFUNDIDAD D C B E F N N A N N N N N Raíz P.2 Salida: RECORRIDO EN PROFUNDIDAD A D C B E F N V N N N N N Raíz V.1 Salida: A RECORRIDO EN PROFUNDIDAD A D E F N V N B N C N N N Raíz V.2 Salida: A RECORRIDO EN PROFUNDIDAD A D C E F N V N B N N N N Raíz V.3 Salida: A Pendiente RECORRIDO EN PROFUNDIDAD A D C B E F N V V N N N N Raíz V.1 Pendiente RECORRIDO EN PROFUNDIDAD A C B E F N V V N N D N N Raíz V.2 Pendiente Salida: A - B RECORRIDO EN PROFUNDIDAD A C B E F N V V N N D N N Raíz V.3 Pendiente Salida: A - B RECORRIDO EN PROFUNDIDAD A D C B E F N V V N V N N Raíz V.1 Salida: A - B - D Pendiente RECORRIDO EN PROFUNDIDAD A D C B F N V V N V N N E Raíz V.2 Pendiente Salida: A - B - D RECORRIDO EN PROFUNDIDAD A D C B F N V V N V N N E Raíz V.3 Pendiente Salida: A - B - D RECORRIDO EN PROFUNDIDAD A D C B E F N V V N V N V Raíz V.1 Salida: A - B - D - E Pendiente RECORRIDO EN PROFUNDIDAD A D B E F N V V N C V N V Raíz V.3 Salida: A - B - D - E RECORRIDO EN PROFUNDIDAD A D C B E F N V V V V N V Raíz V.1 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A C B E F N V V V V D N V Raíz V.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A D C E F N V V B V V N V Raíz P.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A D B E F N V V V C V N V Raíz P.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A C B E F N V V V V D N V Raíz P.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A D C B F N V V V V N V E Raíz P.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A D C B E N V V V V N F V Raíz P.2 Salida: A - B - D - E - C RECORRIDO EN PROFUNDIDAD A D C B E F N V V V V V V Raíz V.1 Salida: A - B - D - E - C - F RECORRIDO EN PROFUNDIDAD private void visitar(Nodo nodoOrigen) { Arista adyacencias; nodoOrigen.estado = 'V'; Console.Write(nodoOrigen.dato + " "); adyacencias = nodoOrigen.ady; while (adyacencias != null) { if (adyacencias.destino.estado == 'N') visitar(adyacencias.destino); adyacencias = adyacencias.sgte; } } public void recorridoProfundidad() { Nodo actual = inicio; inicializarNodos(); while (actual != null){ if (actual.estado == 'N') visitar(actual); actual = actual.sgte; } } P.2 P.1 V.2 V.1 V.3 Algoritmos distribuidos ¡Gracias por su atención!
Compartir