Logo Studenta

Sesión 14 - complemento

¡Este material tiene más páginas!

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!

Continuar navegando