Glab S15 Rusnayo 2023 01
Glab S15 Rusnayo 2023 01
Glab S15 Rusnayo 2023 01
LABORATORIO N° 15
GRAFOS
Alumno Nota
Urquizo Apaza, Josue Alessandro
Grupo D
Fecha de Entrega 03/07/2023
Docente Renato Usnayo Cáceres
OBJETIVOS:
• Conocer, comprender y aplicar el uso de Grafos como una forma de almacenar datos en la
resolución de problemas de software.
SEGURIDAD:
Advertencia:
En este laboratorio está prohibida la manipulación del hardware, conexiones
eléctricas o de red; así como la ingestión de alimentos o bebidas.
FUNDAMENTO TEÓRICO:
• Revisar el texto guía que está en el campus Virtual.
NORMAS EMPLEADAS:
• No aplica
RECURSOS:
• En este laboratorio cada alumno trabajará con un equipo con Windows 10.
PROCEDIMIENTO:
Nota:
Las secciones en cursivas son demostrativas, pero sirven para que usted pueda instalar las
herramientas de desarrollo en un equipo externo.
EJERCICIO DE APLICACIÓN
Los grafos son estructuras de datos que representan relaciones entre elementos. Están compuestos por
nodos (vértices) y arcos (aristas) que conectan los nodos. Python ofrece varias bibliotecas populares
para trabajar con grafos, como NetworkX y igraph. En esta guía, nos centraremos en la biblioteca
NetworkX.
Paso 1: Instalación
Antes de empezar, asegúrate de tener instalada la biblioteca NetworkX en tu entorno de Python. Puedes
instalarlo usando pip:
Comencemos creando un grafo vacío. Importa la biblioteca NetworkX y crea un objeto de grafo:
import networkx as nx
G = nx.Graph()
Hemos creado un grafo no dirigido llamado G. Ahora, podemos agregar nodos y aristas a este grafo.
Para agregar nodos al grafo, utilizamos el método add_node() y pasamos el identificador del nodo como
argumento:
G.add_node(1)
G.add_node(2)
G.add_node(3)
También podemos agregar varios nodos a la vez usando el método add_nodes_from() y pasando una
lista de identificadores:
nodes = [4, 5, 6]
G.add_nodes_from(nodes)
Para agregar aristas, utilizamos el método add_edge() y pasamos los identificadores de los nodos que
queremos conectar:
G.add_edge(1, 2)
G.add_edge(2, 3)
G.add_edge(3, 1)
Del mismo modo, podemos agregar varias aristas a la vez usando el método add_edges_from() y
pasando una lista de pares de nodos:
G.add_edges_from(edges)
Para visualizar el grafo, podemos utilizar la función draw() de NetworkX junto con la biblioteca
Matplotlib. Asegúrate de tener instalada la biblioteca Matplotlib.
nx.draw(G, with_labels=True)
plt.show()
import networkx as nx
import matplotlib.pyplot as plt
# Visualizar el grafo
nx.draw(G, with_labels=True)
plt.show()
Esto mostrará una representación gráfica del grafo con etiquetas en los nodos. Puedes ajustar los estilos
y la disposición del grafo según tus necesidades.
Crea un grafo llamado my_graph con 5 nodos y 6 aristas. Los identificadores de los nodos deben ser
números enteros del 1 al 5. Añade las aristas para que el grafo forme un ciclo cerrado. Luego, visualiza el
grafo utilizando la función draw().
import networkx as nx
import matplotlib.pyplot as plt
my_graph = nx.Graph()
nodes = [1, 2, 3, 4, 5]
edges = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (1, 3)]
my_graph.add_nodes_from(nodes)
my_graph.add_edges_from(edges)
nx.draw(my_graph, with_labels=True)
plt.show()
Este código crea un grafo con 5 nodos y 6 aristas, formando un ciclo cerrado. Luego, se utiliza la función
draw() de NetworkX junto con la biblioteca Matplotlib para visualizar el grafo.
Captura de ejecución
import networkx as nx
import matplotlib.pyplot as plt
my_graph = nx.Graph()
nodes = [1, 2, 3, 4, 5]
edges = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 1), (1, 3)]
my_graph.add_nodes_from(nodes)
my_graph.add_edges_from(edges)
nx.draw(my_graph, with_labels=True)
plt.show()
NetworkX proporciona una amplia gama de funciones para realizar operaciones y consultas en un grafo.
Aquí hay algunos ejemplos:
nodes = G.nodes()
print(nodes)
edges = G.edges()
print(edges)
if G.has_node(1):
print("El nodo 1 está presente en el grafo.")
if G.has_edge(2, 3):
print("La arista entre los nodos 2 y 3 está presente en el grafo.")
Estas son solo algunas de las operaciones básicas disponibles en NetworkX. Puedes consultar la
documentación oficial para obtener más información sobre las operaciones y funciones avanzadas.
nodes = my_graph.nodes()
print("Lista de nodos:", nodes)
edges = my_graph.edges()
print("Lista de aristas:", edges)
if my_graph.has_node(3):
print("El nodo 3 está presente en el grafo.")
else:
print("El nodo 3 no está presente en el grafo.")
if my_graph.has_edge(4, 5):
print("La arista entre los nodos 4 y 5 está presente en el grafo.")
else:
print("La arista entre los nodos 4 y 5 no está presente en el grafo.")
Esto imprimirá la lista de nodos y aristas en el grafo, y verificará la presencia del nodo 3 y la arista entre
los nodos 4 y 5 en el grafo.
import networkx as nx
import matplotlib.pyplot as plt
# Operaciones en el grafo
nodes = my_graph.nodes()
print("Lista de nodos:", nodes)
edges = my_graph.edges()
print("Lista de aristas:", edges)
if my_graph.has_node(3):
print("El nodo 3 está presente en el grafo.")
else:
print("El nodo 3 no está presente en el grafo.")
if my_graph.has_edge(4, 5):
print("La arista entre los nodos 4 y 5 está presente en el grafo.")
else:
print("La arista entre los nodos 4 y 5 no está presente en el grafo.")
class GrafoMatriz:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.matriz = [[0] * num_vertices for _ in range(num_vertices)]
def imprimir_grafo(self):
for fila in self.matriz:
print(fila)
# Ejemplo de uso
grafo = GrafoMatriz(5)
grafo.agregar_arista(0, 1)
grafo.agregar_arista(0, 4)
grafo.agregar_arista(1, 2)
grafo.agregar_arista(1, 3)
grafo.agregar_arista(1, 4)
grafo.agregar_arista(2, 3)
grafo.agregar_arista(3, 4)
grafo.imprimir_grafo()
En este ejemplo, la clase GrafoMatriz representa un grafo utilizando una matriz de adyacencia. La matriz
se inicializa con ceros y tiene un tamaño determinado por el número de vértices proporcionado al
constructor. Luego, puedes utilizar el método agregar_arista para indicar las conexiones entre los
vértices. Finalmente, el método imprimir_grafo muestra la matriz de adyacencia por pantalla.
En el ejemplo de uso, se crea un grafo con 5 vértices y se agregan varias aristas entre ellos. Luego se
imprime la matriz de adyacencia resultante.
Recuerda que en una matriz de adyacencia, el valor 1 indica la existencia de una arista entre dos
vértices, mientras que el valor 0 indica la ausencia de una arista.
Captura de ejecución
import networkx as nx
import matplotlib.pyplot as plt
class GrafoMatriz:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.matriz = [[0] * num_vertices for _ in range(num_vertices)]
def imprimir_grafo(self):
for fila in self.matriz:
print(fila)
grafo = GrafoMatriz(5)
grafo.agregar_arista(0, 1)
grafo.agregar_arista(0, 4)
grafo.agregar_arista(1, 2)
grafo.agregar_arista(1, 3)
grafo.agregar_arista(1, 4)
grafo.agregar_arista(2, 3)
grafo.agregar_arista(3, 4)
grafo.imprimir_grafo()
import networkx as nx
import matplotlib.pyplot as plt
class GrafoMatriz:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.matriz = [[0] * num_vertices for _ in range(num_vertices)]
self.matriz[origen][destino] = 1
self.matriz[destino][origen] = 1
def imprimir_grafo(self):
G = nx.Graph()
for i in range(self.num_vertices):
G.add_node(i)
for i in range(self.num_vertices):
for j in range(i + 1, self.num_vertices):
if self.matriz[i][j] == 1:
G.add_edge(i, j)
# Ejemplo de uso
grafo = GrafoMatriz(5)
grafo.agregar_arista(0, 1)
grafo.agregar_arista(0, 4)
grafo.agregar_arista(1, 2)
grafo.agregar_arista(1, 3)
grafo.agregar_arista(1, 4)
grafo.agregar_arista(2, 3)
grafo.agregar_arista(3, 4)
grafo.imprimir_grafo()
Captura de ejecución
import networkx as nx
import matplotlib.pyplot as plt
class GrafoMatriz:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.matriz = [[0] * num_vertices for _ in range(num_vertices)]
def imprimir_grafo(self):
G = nx.Graph()
for i in range(self.num_vertices):
G.add_node(i)
for i in range(self.num_vertices):
for j in range(i + 1, self.num_vertices):
if self.matriz[i][j] == 1:
G.add_edge(i, j)
grafo = GrafoMatriz(5)
grafo.agregar_arista(0, 1)
grafo.agregar_arista(0, 4)
grafo.agregar_arista(1, 2)
grafo.agregar_arista(1, 3)
grafo.agregar_arista(1, 4)
grafo.agregar_arista(2, 3)
grafo.agregar_arista(3, 4)
grafo.imprimir_grafo()
class Graph:
def __init__(self, num_vertices):
self.num_vertices = num_vertices
self.adj_matrix = [[0] * num_vertices for _ in range(num_vertices)]
self.adj_matrix[source][destination] = 0
self.adj_matrix[destination][source] = 0
def print_graph(self):
for row in self.adj_matrix:
for val in row:
print(val, end=" ")
print()
# Imprimir el grafo
graph.print_graph()
En este ejemplo, la clase Graph representa un grafo y utiliza una matriz de adyacencia adj_matrix para
almacenar las conexiones entre los vértices. El tamaño de la matriz se establece en función del número
de vértices proporcionados al crear el grafo.
El método add_edge permite agregar una conexión entre dos vértices, estableciendo los valores
correspondientes en la matriz de adyacencia. El método remove_edge elimina una conexión existente,
estableciendo los valores correspondientes en la matriz a 0.
El método print_graph imprime la matriz de adyacencia en forma de grafo, donde los valores 1 indican
una conexión entre los vértices correspondientes.
En el ejemplo, se crea un grafo con 5 vértices y se agregan varias conexiones entre ellos. Luego, se
imprime la matriz de adyacencia resultante.
01001
10111
01010
01101
11010
Esta matriz muestra las conexiones entre los vértices del grafo. Por ejemplo, el valor 1 en la posición (0,
1) indica que existe una conexión entre el vértice 0 y el vértice 1, y viceversa.
import networkx as nx
import matplotlib.pyplot as plt
# Dibujar el grafo
pos = nx.spring_layout(G) # Posiciones de los nodos utilizando el algoritmo de Spring layout
nx.draw(G, pos, with_labels=True, node_size=500, node_color='lightblue', font_size=12,
font_weight='bold', edge_color='gray')
# Mostrar el gráfico
plt.title("Grafo")
plt.show()
En este ejemplo, creamos un objeto de grafo G utilizando nx.Graph() de networkx. Luego, agregamos las
conexiones utilizando add_edges_from, donde pasamos una lista de tuplas que representan las
conexiones entre los vértices.
Finalmente, utilizamos nx.draw para dibujar el grafo con las posiciones y opciones de estilo específicas.
with_labels=True muestra los números de los nodos, node_size define el tamaño de los nodos,
node_color establece el color de los nodos, font_size define el tamaño de la fuente y edge_color
establece el color de las conexiones.
Captura de ejecución
Tarea
• Encontrar los nodos a una distancia dada: Escribe una función que tome un grafo y un nodo de
inicio, y encuentre todos los nodos que están a una distancia dada (por ejemplo, 2) desde el
nodo de inicio. Imprime los nodos encontrados.
import networkx as nx
# Ejemplo de uso
G = nx.Graph()
G.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 1)])
start_node = 1
distance = 2
nodes_at_distance = find_nodes_at_distance(G, start_node, distance)
print("Nodos a una distancia de", distance, "desde el nodo", start_node,
":", nodes_at_distance)
• Verificar si un grafo es conexo: Escribe una función que tome un grafo como entrada y verifique
si el grafo es conexo. Un grafo es conexo si existe un camino entre cualquier par de nodos.
import networkx as nx
def is_connected(graph):
return nx.is_connected(graph)
# Ejemplo de uso
G = nx.Graph()
G.add_edges_from([(1, 2), (2, 3), (3, 1)])
if is_connected(G):
print("El grafo es conexo.")
else:
print("El grafo no es conexo.")
• Encontrar el camino más corto: Escribe una función que tome un grafo y dos nodos como
entrada, y encuentre el camino más corto entre los dos nodos utilizando el algoritmo de
Dijkstra. Imprime el camino más corto encontrado.
import networkx as nx
# Ejemplo de uso
G = nx.Graph()
G.add_edges_from([(1, 2), (2, 3), (3, 4), (4, 5)])
start_node = 1
end_node = 5
shortest_path = find_shortest_path(G, start_node, end_node)
print("Camino más corto entre el nodo", start_node, "y el nodo", end_node,
":", shortest_path)
OBSERVACIONES:
1. Los grafos son una estructura de datos utilizada para representar relaciones o conexiones entre
elementos.
2. Los grafos se componen de nodos (vértices) y aristas (arcos) que conectan los nodos.
3. Existen varios tipos de grafos, como grafos dirigidos y no dirigidos, grafos ponderados y grafos
cíclicos o acíclicos.
4. Los grafos tienen muchas aplicaciones prácticas en diversos campos. Por ejemplo, en redes
sociales, los nodos pueden representar usuarios y las aristas las conexiones de amistad. En
logística, los nodos pueden ser ubicaciones y las aristas los caminos entre ellas.
5. Los grafos plantean una variedad de problemas y desafíos algorítmicos interesantes.
CONCLUSIONES:
1. Los grafos son una estructura de datos versátil y poderosa que permite representar y analizar
una amplia gama de relaciones y conexiones en diversos contextos.
2. Los grafos ofrecen una forma abstracta de modelar relaciones y conexiones, lo que permite
simplificar y comprender mejor problemas complejos.
3. Existen numerosos algoritmos y técnicas diseñados específicamente para trabajar con grafos, lo
que permite resolver problemas de manera eficiente.
4. Los grafos son especialmente útiles para modelar sistemas complejos, donde múltiples
elementos interactúan entre sí.
5. los grafos pueden parecer abstractos a primera vista, tienen muchas aplicaciones prácticas en la
vida cotidiana.