Actividad Práctica#2
Actividad Práctica#2
Actividad Práctica#2
Asignatura:
Análisis y Diseño de Algoritmos
Componente:
Actividades Prácticas y de Experimentación
Integrantes:
➢ Arteaga Arteaga Yanelly Doménica
➢ Fernández Peralta Cesar Augusto
➢ Navarrete Barragán Jhon Eduardo
➢ Molina Guillem Fernando José
➢ Serrano Macias Ernesto David
➢ Zambrano Bravo Merly Paola
Actividad:
Resolver los siguientes problemas:
1. Muestre los valores d y π que resultan de ejecutar la búsqueda de amplitud primero
en el grafo dirigido de la siguiente figura, utilizando el vértice 3 como origen.
1/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
3. Muestre que usar un solo bit para almacenar cada color de vértice es suficiente
argumentando que el procedimiento BFS produce el mismo resultado si se elimina
la línea 18. Luego muestre cómo obviar la necesidad de colores de vértice por
completo.
Eliminar la línea 18 del código proporcionado significaría que los vértices nunca se
marcan como explorados completamente. Esto significa que no podrías diferenciar
entre los vértices que están detrás de la frontera y aquellos que están
completamente explorados. Sin embargo, el recorrido central de BFS seguiría
funcionando como se esperaba, ya que se basa en la cola (líneas 10-17) y no
depende explícitamente de los colores de los vértices.
u.d = float('inf')
u.π = None
s.d = 0
s.π = None
Q = []
Q.append(s)
visitados = set()
visitados.add(s)
while Q:
u = Q.pop(0)
for v in G.Adj[u]:
2/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
if v not in visitados:
v.d = u.d + 1
v.π = u
Q.append(v)
visitados.add(v)
En una matriz de adyacencia, cada celda (i, j) representa una arista entre el vértice
i y el vértice j. Si el grafo es no dirigido y no ponderado, la matriz de adyacencia es
simétrica, y cada entrada contiene un 0 o un 1 para indicar la ausencia o presencia
de una arista.
visitados[inicio] = True
distancia[inicio] = 0
cola.append(inicio)
while cola:
u = cola.popleft() # Obtenemos el vértice en el frente de la cola
for v in range(n):
# Verificamos si hay una arista entre u y v en la matriz de adyacencia
if matriz[u][v] == 1 and not visitados[v]:
visitados[v] = True
distancia[v] = distancia[u] + 1
cola.append(v)
return distancia
# Ejemplo de uso:
matriz_de_adyacencia = [
[0, 1, 1, 0, 0],
[1, 0, 1, 1, 0],
[1, 1, 0, 0, 1],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0]
]
3/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
distancias = BFS_matriz_de_adyacencia(matriz_de_adyacencia, inicio)
print("Distancias desde el vértice {} a todos los demás vértices:".fo rmat(inicio))
print(distancias)
V = {s, a, b, c, d} E = {(s, a), (s, b), (a, c), (a, d), (b, c), (c, d)}
Para crear el conjunto de aristas del árbol Eπ de manera que para cada vértice v ∈ V,
el camino simple único en el grafo (V, Eπ) desde s hasta v sea un camino más corto
en G, podemos elegir las siguientes aristas:
Ahora, analicemos por qué este conjunto de aristas del árbol Eπ no se puede obtener
ejecutando BFS en G, sin importar cómo ordenemos los vértices en las listas de
adyacencia.
4/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
Cuando ejecutamos BFS desde el vértice fuente s en este grafo G, BFS visitará los
vértices en el orden s, a, b, c, d. Sin embargo, BFS producirá el siguiente conjunto de
aristas del árbol:
Aristas del árbol BFS = {(s, a), (s, b), (a, c), (a, d), (b, c)}
Comparando las aristas del árbol BFS con nuestras Eπ elegidas, podemos ver que no
son iguales. Específicamente, el árbol BFS incluye una arista adicional (b, c) que no
está en Eπ. Esto significa que el conjunto de aristas Eπ que elegimos no se puede
obtener ejecutando BFS en este grafo G, independientemente de cómo ordenemos
los vértices en las listas de adyacencia.
grafo = defaultdict(list)
grafo[luchador1].append(luchador2)
grafo[luchador2].append(luchador1)
colores = {}
colores[luchador] = color
if rival in colores:
if colores[rival] == color:
5/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
return False
else:
return False
return True
# Ejemplo de uso:
n = 5 # Número de luchadores
rivalidades = [(1, 2), (2, 3), (3, 4), (4, 5), ( 5, 1)] # Pares de luchadores con
rivalidades
print(resultado)
Este algoritmo realiza BFS para colorear a los luchadores de manera que ningún par
de luchadores adyacentes tenga el mismo color (cara y villano). Si es imposible
hacerlo, devuelve "Imposible". De lo contrario, devuelve las caras y los villanos
designados.
class Grafo:
def __init__(self):
self.grafo = defaultdict(list)
self.grafo[u].append(v)
self.grafo[v].append(u)
visitados = set()
pila = [(inicio, 0)] # Usamos una pila para DFS y llevamos un seguimiento de la
distancia
maxima_distancia = (inicio, 0)
while pila:
visitados.add(nodo)
return maxima_distancia
def diametro_del_arbol(self):
vertice_mas_lejano1, _ = self.DFS(list(self.grafo.keys())[0])
7/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
vertice_mas_lejano2, diametro = self.DFS(vertice_mas_lejano1)
return diametro
# Ejemplo de uso:
arbol = Grafo()
arbol.agregar_arista(1, 2)
arbol.agregar_arista(1, 3)
arbol.agregar_arista(2, 4)
arbol.agregar_arista(2, 5)
arbol.agregar_arista(3, 6)
arbol.agregar_arista(5, 7)
arbol.agregar_arista(7, 8)
diametro = arbol.diametro_del_arbol()
9. Haga un gráfico de 3 por 3 con etiquetas de fila y columna BLANCO, GRIS y NEGRO.
En cada celda (i, j), indique si, en cualquier punto durante una búsqueda en
profundidad de un grafo dirigido, puede haber una arista desde un vértice de color i
hasta un vértice de color j. Para cada arista posible, indique qué tipos de arista
puede ser. Haga un segundo gráfico de este tipo para la búsqueda de profundidad de
un gráfico no dirigido.
Grafo dirigido:
Nodo j
Desde/Hasta Blanco Gris Negro
Árbol
Atrás Atrás
Blanco Cruz
Adelante Cruz
Cruz
Nodo Árbol
i Árbol Árbol
Atrás
Gris Adelante Cruz
Adelante
Cruz Adelante
Cruz
Árbol
Atrás Cruz
Negro Cruz Adelante
Atrás
8/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
Grafo no dirigido:
Nodo j
Desde/Hasta Blanco Gris Negro
Árbol Árbol
Nodo Blanco Atrás Atrás
i Árbol Árbol Árbol
Gris Atrás Atrás Atrás
Árbol Árbol
Negro Atrás Atrás
Se registraron los tiempos de descubrimiento (d) y finalización (f) de cada vértice, así
como la clasificación de las aristas:
(q): Vértice q se descubre primero (d=1) y se finaliza después (f=14). Las aristas que
salen de q son de tipo árbol.
(s): Vértice s se descubre después de q (d=2) y se finaliza antes (f=5). La arista de q a
s es de tipo árbol.
(v): Vértice v se descubre después de s (d=3) y se finaliza antes (f=4). La arista de s a
v es de tipo árbol.
(w): Vértice w se descubre después de s (d=6) y se finaliza antes (f=9). Las aristas de
q a w y de v a w son de tipo árbol.
(z): Vértice z se descubre después de x (d=11) y se finaliza después (f=12). La arista
de x a z es de tipo árbol.
(x): Vértice x se descubre después de t (d=10) y se finaliza después (f=13). La arista
de t a x es de tipo árbol.
(t): Vértice t se descubre después de q (d=7) y se finaliza antes (f=8). La arista de q a t
es de tipo árbol.
(y): Vértice y se descubre después de t (d=15) y se finaliza después (f=16). Las aristas
de t a y y de r a y son de tipo árbol.
(r): Vértice r se descubre después de t (d=17) y se finaliza antes (f=18). Las aristas de
t a r y de r a u son de tipo árbol.
(u): Vértice u se descubre después de r (d=19) y se finaliza después (f=20). La arista
de r a u es de tipo árbol.
11. Aplique y muestra la estructura de agrupación entre paréntesis de la búsqueda
en profundidad para el siguiente grafo.
9/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
(u)
(v)
(y)
(x)
(w)
(z)
(u)
(v)
(y)
(w)
(z)
(x)
DFS-VISIT(G, u)
time = time + 1 // El vértice blanco U acaba de ser descubierto
u.d = time
u.color = GRIS
desde cada vértice v en G.Adj[u] // Explora cada arista (U, V)
si v.color == BLANCO
v.π = u
DFS-VISIT(G,v)
time = time + 1
u.f = time
10
La eliminación de la línea 10, que cambia el color del vértice a "NEGRO" al concluir
su exploración en el algoritmo DFS, tiene principalmente la función de indicar que
el vértice ha finalizado su procesamiento y no tiene más aristas por explorar. Esto
ayuda a mantener un seguimiento del estado de los vértices durante la ejecución
10
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
del algoritmo. No altera el resultado correcto del algoritmo DFS en cuanto a los
tiempos de descubrimiento y finalización de los vértices, ni en lo que respecta a la
clasificación de las aristas. Esto se debe a que los tiempos de descubrimiento y
finalización continúan registrándose de manera adecuada en las líneas 2 y 9,
respectivamente, y la línea 3 todavía marca el vértice como "GRIS" al ser
descubierto, indicando que se encuentra en proceso.
a) una arista árbol o una arista de avance si y sólo si u.d < v.d < v.f < u.f,
14. Vuelva a escribir el procedimiento DFS, utilizando una pila para eliminar la recursión.
def DFS(G):
for u in G.V:
u.color = BLANCO
u.π = NIL
time = 0
stack = [] # Utilizamos una pila en lugar de la recursión
for u in G.V:
if u.color == BLANCO:
stack.append(u)
while stack:
current_vertex = stack[-1]
if current_vertex.color == BLANCO:
time += 1
current_vertex.d = time
current_vertex.color = GRIS
11
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
found = False
for v in G.Adj[current_vertex]:
if v.color == BLANCO:
v.π = current_vertex
stack.append(v)
found = True
break
if not found:
stack.pop()
time += 1
current_vertex.f = time
current_vertex.color = NEGRO
Este procedimiento DFS utiliza una pila para llevar a cabo la búsqueda en
profundidad de manera no recursiva. Al encontrar un vértice blanco, lo marcamos
como gris, lo exploramos y agregamos sus vecinos blancos a la pila. Cuando no hay
más vecinos blancos, marcamos el vértice como negro y lo eliminamos de la pila.
Esto se repite hasta que se haya explorado todo el grafo.
A -> B
A -> C
B -> D
C -> D
Ahora, supongamos que queremos encontrar un camino desde A a D en este grafo
utilizando una búsqueda en profundidad (DFS).
Comenzamos la búsqueda en A y recorremos las aristas en orden alfabético:
Desde A, visitamos B (A -> B) y marcamos B como visitado.
Desde B, visitamos D (B -> D) y marcamos D como visitado.
En este punto, hemos encontrado un camino de A a D: A -> B -> D.
Ahora, veamos los tiempos de descubrimiento (d) de los vértices:
A: d(A) = 1
B: d(B) = 2
D: d(D) = 3
Vemos que u.d (A.d) es menor que v.d (D.d), ya que 1 < 3. Sin embargo, en el
bosque producido por la búsqueda en profundidad, D no es un descendiente de A.
De hecho, D se encuentra en un nivel más bajo que A en el grafo de búsqueda en
profundidad.
A -> B
A -> C
B -> D
C -> D
12
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
Ahora, supongamos que queremos encontrar un camino desde A a D en este grafo
utilizando una búsqueda en profundidad (DFS).
Comenzamos la búsqueda en A y recorremos las aristas en orden alfabético:
Desde A, visitamos B (A -> B) y marcamos B como visitado.
Desde B, visitamos D (B -> D) y marcamos D como visitado.
En este punto, hemos encontrado un camino de A a D: A -> B -> D.
Ahora, veamos los tiempos de descubrimiento y finalización de los vértices:
A: Descubrimiento (A.d) = 1, Finalización (A.f) = 4
B: Descubrimiento (B.d) = 2, Finalización (B.f) = 3
D: Descubrimiento (D.d) = 3, Finalización (D.f) = 2
Entonces, v.d (D.d) es mayor que u.f (A.f), lo que contradice la afirmación de que
v.d debe ser menor o igual que u.f para cualquier búsqueda en profundidad. En
este caso, tenemos un camino de A a D en el grafo, pero v.d (D.d) es mayor que u.f
(A.f).
Algoritmo BusquedaEnProfundidad(G)
visitados = lista vacía
FinAlgoritmo
13
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
La clave para entender esto es que un árbol de búsqueda en profundidad se
construye explorando las aristas de salida de un vértice en particular antes de
retroceder y explorar otras ramas. Si las aristas de salida desde u no conducen a
otros vértices que puedan alcanzarse a través de una búsqueda en profundidad, el
árbol de búsqueda resultante solo incluirá al vértice u.
19. Sea G = (V, E) un grafo conexo no dirigido. Proporcione un algoritmo de tiempo O(V
+ E) para calcular un camino en G que atraviese cada arista en E exactamente una
vez en cada dirección. Describa cómo puede encontrar la manera de salir de un
laberinto si se le da un gran suministro de centavos.
Para calcular un camino en un grafo conexo no dirigido que atraviese cada borde en
E exactamente una vez en cada dirección, puedes utilizar el algoritmo del recorrido
en profundidad (DFS, por sus siglas en inglés) modificado. Aquí hay un algorit mo de
tiempo O(V + E) para lograr esto:
1. Crea una lista vacía llamada "camino" para almacenar el camino resultante.
3. Inicia el DFS desde el vértice inicial. Para cada borde no visitado que
encuentres durante el recorrido, añádelo al camino y marca el borde como
visitado.
5. Repite los pasos 3 y 4 hasta que hayas visitado todos los bordes del grafo.
20. Mostrar cómo usar una búsqueda de profundidad de un grafo G no dirigido para
identificar los componentes conectados de G, de modo que el bosque de
profundidad primero contenga tantos árboles como G tiene componentes
conectados. Más precisamente, muestra cómo modificar la búsqueda de
profundidad primero para que asigne a cada vértice v una etiqueta entera v.cc entre
1 y k, donde k es el número de componentes conectados de G, tal que u.cc = v.cc si y
solo si u y v pertenecen al mismo componente conectado.
3. En la función DFS-CC(v, k): Asignar a v una etiqueta entera v.cc igual al valor
actual de k. Marcar v como visitado. Para cada vecino u de v, si u no ha sid o
visitado, llamar recursivamente a DFS-CC(u, k).
EJEMPLO EN PSEUDOCODIGO
DFS-CC(v, k):
v.cc = k
marcar v como visitado
para cada vecino u de v:
si u no ha sido visitado:
DFS-CC(u, k)
Búsqueda-CC(G):
k=0
para cada vértice v en G:
si v no ha sido visitado:
k=k+1
DFS-CC(v, k)
Por lo tanto, el orden resultante del ordenamiento topológico, siguiendo las reglas
que mencionaste y las listas de adyacencia ordenadas alfabéticam ente, sería: m, n,
o, p, q, r, s, t, u, v, w, x, y, z.
22. Dé un algoritmo de tiempo lineal que, dado un grafo acíclico dirigido G = (V, E) y
dos vértices a, b ∈ V, devuelve el número de caminos simples de a hacia b en G. Por
ejemplo, el grafo acíclico dirigido de la figura en el ejercicio anterior contiene
exactamente cuatro caminos simples desde el vértice p hasta el vértice v: 〈p, o, v〉,
15
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
〈p, o, r, y, v〉, 〈p, o, s, r, y, v〉 y 〈p, s, r, y, v〉. Su algoritmo solo necesita contar las rutas
simples, no enumerarlas.
Este algoritmo utiliza una lista llamada "visitados" para almacenar los vértices
visitados durante el recorrido y una cola para realizar la búsqueda en amplitud.
Comienza eligiendo un vértice inicial arbitrario y lo agrega tanto a la lista de
"visitados" como a la cola. Luego, repite el proceso de sacar un vértice de la cola y
agregar sus vértices adyacentes no visitados a la lista de "visitados" y a la cola. Al
final, verifica si todos los vértices del grafo están en la lista de "visitados" para
determinar si el grafo es conexo individualmente.
Algoritmo EsConexoIndividualmente(G)
visitados = lista vacía
cola = cola vacía
#include <stdbool.h>
16
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
return false;
}
return false;
}
int main() {
// Definir tu grafo como matriz de adyacencia G
// int G[V][V] = ...
if (tieneCicloSimple(G)) {
printf("El grafo contiene un ciclo simple.\n");
} else {
printf("El grafo no contiene un ciclo simple.\n");
}
return 0;
}
24. Probar o refutar: Si un grafo dirigido G contiene ciclos, entonces el orden de vértices
producido por TOPOLOGICAL-SORT(G) minimiza el número de aristas "malas" que
son inconsistentes con el orden producido.
a b
\ /
\/
c
/\
d e
17
/5
Universidad Técnica de Manabí
Facultad de Ciencias Informáticas
Carrera de Sistemas de Información
Algoritmo OrdenTopologicoKahn(G):
Inicializar cola
Inicializar OrdenTopologico
Grafo ejemplo:
V = {a, b, c, d, e}
E = {(a, c), (b, c), (c, d), (c, e)}
OrdenTopologicoKahn(Grafo)
18
/5