Está en la página 1de 6

Problema de Coloreo de Grafos (PCG)

Diwsgen López Lozada Jesús Huerta Aguilar Juan Pablo Hernández Flores
Benemérita Universidad autónoma de Benemérita Universidad autónoma de Benemérita Universidad autónoma de
Puebla Puebla Puebla
FCC FCC FCC
202043856 202041509 202068295
diwsgen.lopez@alumno.buap.mx jesus.huertaag@alumno.buap.mx juan.hernandezfl@alumno.buap.mx

Juan Martínez Díaz


Benemérita Universidad autónoma de
Puebla
FCC
202045427
juan.martinezdiad@alumno.buap.mx

RESUMEN presentarán implementaciones en Python de estos algoritmos, y se


discutirán las ventajas y desventajas de cada uno. Además, se
El Problema de Coloreo de Grafos es uno de los problemas más explorarán algunas aplicaciones prácticas de estos algoritmos,
estudiados en teoría de grafos, y consiste en asignar un color a cada como el análisis de redes sociales y la búsqueda de caminos en un
vértice de un grafo de tal manera que dos vértices adyacentes no laberinto.
tengan el mismo color. En este trabajo, se discutirán dos algoritmos
de búsqueda en grafos, DFS y BFS, que son fundamentales para el
problema de coloreo de grafos, y se presentarán implementaciones INTRODUCCIÓN
en Python de estos algoritmos. También se mostrará cómo estos
El Problema de coloreo de grafos es uno de los problemas más
algoritmos se pueden utilizar para resolver el problema de coloreo
estudiados en teoría de grafos. Consiste en asignar un color a cada
de grafos.
vértice de un grafo de tal manera que dos vértices adyacentes no
tengan el mismo color. Este problema tiene diversas aplicaciones
PALABRAS CLAVE prácticas en áreas como la planificación de horarios de clases,
Grafos, Programación, Algoritmos, Problema, Computación asignación de recursos limitados y diseño de redes de
comunicación.

ABSTRACT Para resolver el problema de coloreo de grafos, existen diferentes


The Graph Coloring Problem is one of the most studied problems algoritmos y técnicas. En este artículo, nos centraremos en dos de
in graph theory, and consists of assigning a color to each vertex of los algoritmos de búsqueda en grafos más fundamentales: DFS
a graph in such a way that two adjacent vertices do not have the (Depth-First Search) y BFS (Breadth-First Search), y cómo se
same color. In this paper, we will discuss two graph search pueden implementar en Python para resolver el problema de
algorithms, DFS and BFS, which are fundamental for the Graph coloreo de grafos.
Coloring Problem, and present Python implementations of these
algorithms. We will also show how these algorithms can be used to
solve the Graph Coloring Problem.

KEYWORDS
Graphs, Programming, Algorithms, Problem, Computing

OBJETIVO
El objetivo de este trabajo es presentar una introducción al
Problema de Coloreo de Grafos y dos algoritmos de búsqueda en Ilustración 1: Diferencias entre BFS y DFS
grafos, DFS y BFS, y mostrar cómo estos algoritmos se pueden
utilizar para resolver el problema de coloreo de grafos. Se
BUAP, marzo 2023, Puebla, Puebla MEXICO Fernando Zacarias Flores.

DFS es un algoritmo de búsqueda en grafos que funciona Los algoritmos BFS y DFS han sido utilizados para resolver
explorando tan lejos como sea posible a lo largo de cada rama antes muchos problemas de coloreo de grafos. El algoritmo BFS es
de retroceder. Es decir, se trata de un algoritmo de recorrido en utilizado para determinar el número cromático de un grafo,
profundidad que se utiliza para visitar todos los vértices de un mientras que el algoritmo DFS es utilizado para asignar colores a
grafo. Por otro lado, BFS es un algoritmo de búsqueda en grafos los vértices del grafo. Estos algoritmos son muy eficientes y se han
que explora primero todos los vértices adyacentes al vértice inicial utilizado en muchos campos diferentes, como la programación de
antes de avanzar en profundidad. Es decir, es un algoritmo de horarios, la asignación de frecuencias en redes de comunicaciones,
recorrido en anchura que se utiliza para visitar todos los vértices de la programación de rutas de transporte y la planificación de
un grafo. ensamblajes en la fabricación.

En este artículo, se presentarán implementaciones de ambos Aunque el problema de coloreo de grafos es NP-completo, los
algoritmos en Python y se explicará cómo se pueden utilizar para algoritmos BFS y DFS han sido fundamentales en la resolución de
resolver el problema de coloreo de grafos. Se analizará la muchos casos del problema de manera eficiente. La teoría de grafos
complejidad de cada algoritmo y se mostrarán ejemplos prácticos y la informática teórica siguen siendo un campo activo de
de su aplicación en diferentes problemas de coloreo de grafos. investigación y desarrollo de algoritmos para resolver problemas
cada vez más complejos. Los algoritmos BFS y DFS son solo
En resumen, el problema de coloreo de grafos es un tema algunos de los muchos algoritmos que se han desarrollado en este
importante en la teoría de grafos y tiene aplicaciones prácticas en campo y que continúan siendo utilizados en la actualidad para
diversas áreas. DFS y BFS son algoritmos fundamentales para resolver problemas de coloreo de grafos y otros problemas
resolver este problema, y su implementación en Python puede relacionados con la teoría de grafos.
resultar útil en la resolución de problemas de coloreo de grafos en
diferentes situaciones.

PROBLEMA DE COLOREO DE GRAFOS


El problema de coloreo de grafos es uno de los problemas más
conocidos y estudiados en la teoría de grafos. La idea es asignar un
color a cada vértice de un grafo, de tal manera que los vértices
adyacentes tengan colores diferentes. El objetivo es minimizar el
número de colores utilizados para colorear el grafo. Aunque el
problema de coloreo de grafos es NP-completo, se han desarrollado
varios algoritmos que pueden resolver muchos casos del problema
de manera eficiente. Entre estos algoritmos se encuentran el BFS y
el DFS, dos algoritmos que han sido fundamentales en la resolución
de muchos problemas de coloreo de grafos.

El algoritmo BFS (Breadth-First Search) es un algoritmo que se Ilustración 2: Coloración de vértices para el grafo Petersen
utiliza para recorrer y buscar elementos en un grafo. El algoritmo utilizando tres colores
comienza por el nodo inicial y visita todos los nodos adyacentes
antes de pasar a los nodos más distantes. El algoritmo BFS es CODIGO BFS
utilizado en el problema de coloreo de grafos para determinar el Este código implementa una búsqueda por amplitud (BFS) en un
número cromático de un grafo, que es el número mínimo de colores grafo dado en Python. También muestra cómo dibujar el grafo
que se necesitan para colorear el grafo de manera que ningún utilizando la biblioteca NetworkX y la biblioteca de visualización
vértice adyacente tenga el mismo color. de gráficos matplotlib.

El algoritmo DFS (Depth-First Search) es otro algoritmo utilizado import networkx as nx


en la teoría de grafos para recorrer y buscar elementos en un grafo. import matplotlib.pyplot as plt

El algoritmo comienza en un nodo inicial y explora todo el grafo


hasta que no hay más nodos por visitar. El algoritmo DFS se utiliza En la primera sección del código, se define el grafo de ejemplo
en el problema de coloreo de grafos para asignar colores a los como un diccionario con nodos y sus conexiones. Después se
vértices del grafo. El algoritmo asigna un color al vértice actual y define la clase MyQUEUE, que es una implementación básica de una
luego recursivamente asigna colores a todos los vértices cola para ser utilizada en el algoritmo BFS. Esta clase tiene tres
adyacentes. Si el algoritmo encuentra un vértice que no se puede métodos: __init__, enqueue, dequeue, e IsEmpty. El
colorear con el color actual, retrocede y prueba con un color método __init__ inicializa la cola, mientras que enqueue
diferente. agrega un elemento al final de la cola. El método dequeue saca el

2
Magnetic Normal Modes of Bi-Component Permalloy Structures WOODSTOCK’97, July 2016, El Paso, Texas USA

primer elemento de la cola y lo devuelve, mientras que IsEmpty Después de la definición de la función BFS, se llama a la función
verifica si la cola está vacía. BFS con el grafo dado, el nodo de inicio "A", el nodo de
finalización "D" y la cola path_queue. La distancia calculada
# a sample graph entre el nodo de inicio y el nodo de finalización se almacena en el
graph = {'A': ['B', 'C', 'E'],
'B': ['A', 'C', 'D'], diccionario distances y se imprime en la pantalla.
'C': ['D'],
'D': ['C'],
'E': ['F', 'D'], distances = BFS(graph, "A", "D", path_queue)
'F': ['C']} print("Distances:", distances)

class MyQUEUE: # just an implementation of a queue


def __init__(self):
self.holder = [] Luego, se define la función printGraph, que toma el objeto de
def enqueue(self,val):
self.holder.append(val) grafo, la disposición de los nodos y el diccionario de distancias
def dequeue(self): como argumentos, y dibuja el grafo utilizando la biblioteca
val = None
try:
NetworkX y la biblioteca de visualización de gráficos matplotlib.
val = self.holder[0] Esta función primero dibuja los nodos del grafo con diferentes
if len(self.holder) == 1: tamaños y colores. Luego, dibuja las conexiones entre los nodos
self.holder = []
else: con flechas, y agrega etiquetas de nodos en el grafo que contienen
self.holder = self.holder[1:] el nombre del nodo y su distancia desde el nodo de inicio.
except:
pass Finalmente, la función muestra el gráfico.

return val # Funcion para dibujar el grafo


def IsEmpty(self): def printGraph(G, pos, distances):
result = False # positions for all nodes
if len(self.holder) == 0: # nodes
result = True nx.draw_networkx_nodes(G, pos, node_size=500,
return result node_color='#8FBC8F')

# edges
A continuación, se define la función BFS, que implementa el nx.draw_networkx_edges(G, pos, width=1, arrows=True,
algoritmo BFS en el grafo dado. Esta función toma el grafo, el nodo arrowsize=20, arrowstyle='->')

de inicio, el nodo de finalización y la cola MyQUEUE como # labels


argumentos. En primer lugar, inicializa un diccionario dist con el labels = {node: f"{node}, {distances[node]}" for node
in G.nodes()}
nodo de inicio y su distancia a cero, y luego agrega el nodo de inicio nx.draw_networkx_labels(G, pos, labels, font_size=10,
a una lista temporal temp_path y la agrega a la cola q. Luego, font_family='cursive')

mientras la cola no esté vacía, la función extrae el primer elemento plt.axis('off')


de la cola y lo asigna a tmp_path. La función luego obtiene el plt.show()

último nodo en tmp_path y verifica si es el nodo de finalización.


Si es así, la función imprime VALID_PATH y la ruta temporal. De Por último, se crea un objeto Graph de NetworkX con el
lo contrario, la función agrega los nodos adyacentes al último nodo diccionario graph dado y se llama a la función printGraph con
a la cola si no han sido visitados antes y actualiza sus distancias en el objeto del grafo, la disposición de los nodos y el diccionario de
el diccionario dist. La función continúa este proceso hasta que la distancias calculado anteriormente.
cola esté vacía. # Crear un objeto Graph de NetworkX
G = nx.Graph(graph)
path_queue = MyQUEUE() # now we make a queue pos = nx.shell_layout(G)

def BFS(graph, start, end, q): printGraph(G, pos, distances)


dist = {start: 0}
temp_path = [start]
q.enqueue(temp_path) EJECUCIÓN: CODIGO BFS
while not q.IsEmpty(): El código implementa el algoritmo BFS (Breadth-First Search) para
tmp_path = q.dequeue() encontrar la distancia más corta entre dos nodos en un grafo no
last_node = tmp_path[-1]
print (" ",tmp_path) dirigido. El grafo utilizado es un ejemplo simple representado como
if last_node == end: un diccionario de listas de adyacencia.
print ("VALID_PATH:", tmp_path)
for link_node in graph[last_node]:
if link_node not in dist: Primero, se define una clase de cola (MyQUEUE) para ser utilizada
dist[link_node] = dist[last_node] + 1
new_path = tmp_path + [link_node] en BFS. Luego, la función BFS toma el grafo, el nodo inicial y final,
q.enqueue(new_path) y una cola como entrada, y devuelve un diccionario de distancias
return dist
de nodos desde el nodo inicial. La función también imprime la ruta
desde el nodo inicial hasta el nodo final.

3
BUAP, marzo 2023, Puebla, Puebla MEXICO Fernando Zacarias Flores.

'8' : []
}

visited = set() # Configurado para realizar un


seguimiento de los nodos visitados del gráfico.

la función "dfs" es una función de búsqueda en profundidad que


recorre el grafo y muestra los nodos visitados y sus distancias desde
el nodo de inicio. La función actualiza también la distancia del
Ilustración 3: Ruta del nodo inicial al nodo final vecino si su distancia desde el nodo actual es mayor. La función
DFS se llama para el grafo definido anteriormente, comenzando en
Después de llamar a la función BFS, el código dibuja el grafo el nodo '5' y se muestra en la consola.
utilizando la biblioteca NetworkX. El tamaño y el color de los
def dfs(visited, graph, node, distance): #funcion para
nodos se establecen en la función printGraph, y las etiquetas de dfs
nodo se establecen en función de la distancia de nodo calculada por if node not in visited:
visited.add(node)
BFS. print (f"Nodo: {node} Distancia:
{distance[node]}")
for neighbour in graph[node]:
distance[neighbour] = distance[node] + 1 #
Actualizar la distancia del vecino
dfs(visited, graph, neighbour, distance)

# Codigo
print("A continuación se muestra el algoritmo DFS")
start_node='5'
distance = {start_node: 0}
dfs(visited, graph, start_node, distance)

La función "printGraph" es una función que toma un objeto de


grafo de NetworkX, una posición de nodos y las distancias de los
nodos del nodo de inicio y dibuja el grafo correspondiente.

#Funcion para dibujar el grafo


def printGraph(G2, pos, distances=None):
# positions for all nodes

# nodes
nx.draw_networkx_nodes(G2, pos,
node_size=500,node_color='#8FBC8F')

Ilustración 4: Grafo final # edges


nx.draw_networkx_edges(G2, pos,
width=1,arrows=True,arrowsize=20,arrowstyle='->')
En resumen, el código encuentra la distancia más corta entre dos
# Mostrar las distancias en los nodos
nodos en un grafo y lo visualiza en una gráfica. labels = {node: f"{node},{distances[node]}" for node
in G.nodes()}
nx.draw_networkx_labels(G, pos, labels, font_size=10,
CODIGO DFS font_family='cursive')
networkx es una biblioteca de Python para la creación, plt.axis('off')
manipulación y visualización de estructuras de redes complejas. plt.show()
matplotlib.pyplot es una biblioteca para crear gráficos y
trazar visualizaciones. Crear un objeto Graph de NetworkX: un objeto de grafo de
NetworkX se crea a partir del diccionario de grafo "graph" y se
import networkx as nx llama "G". La posición de los nodos se define mediante la función
import matplotlib.pyplot as plt
"shell_layout" de NetworkX. La función "printGraph"
Definir el grafo: el grafo se define como un diccionario llamado se llama para el objeto de grafo "G", la posición de los nodos "pos"
"graph" con las claves como los nodos y los valores como las y las distancias del nodo de inicio.
listas de los vecinos de cada nodo. # Crear un objeto Graph de NetworkX
G = nx.Graph(graph)
graph = { pos = nx.shell_layout(G)
'5' : ['3','7'], printGraph(G, pos, distance)
'3' : ['2', '4'],
'7' : ['8'], # Mostrar el grafo en pantalla
'2' : [], plt.show()
'4' : ['8'],

4
Magnetic Normal Modes of Bi-Component Permalloy Structures WOODSTOCK’97, July 2016, El Paso, Texas USA

La función "recursive_dfs" es una versión recursiva de la Un objeto de grafo de NetworkX se crea a partir del segundo
función DFS. Toma un grafo, un nodo fuente, una lista de nodos diccionario de grafo "graph2" y se llama "G2", después se define la
visitados y un diccionario de distancias de nodos, y devuelve una posición de los nodos.
lista de nodos visitados y el diccionario de distancias.
# Crear un objeto Graph de NetworkX
G2 = nx.Graph(graph2)
# Aqui inicia el dfs recursivo pos = nx.shell_layout(G2)
def recursive_dfs(graph, source, path=[], distance={}):
if source not in path:
printGraph2(G2, pos, distances)
path.append(source)
if source not in graph:
# Nodo hoja, retroceder
return path, distance
for neighbour in graph[source]:
if neighbour not in distance or
EJECUCIÓN: CODIGO DFS
distance[neighbour] > distance[source] + 1: El código dado implementa dos algoritmos de búsqueda de
distance[neighbour] = distance[source] +
1 # Actualizar la distancia del vecino profundidad primero (DFS) en dos grafos diferentes utilizando la
path, distance = recursive_dfs(graph, biblioteca NetworkX de Python.
neighbour, path, distance)
return path, distance

El segundo grafo se define como un diccionario llamado "graph2"


con las claves como los nodos y los valores como las listas de los
vecinos de cada nodo. El diccionario "distances" se define para
tener una distancia de 0 para el nodo de inicio "A" y un valor
infinito para los demás nodos.

graph2 = {"A":["B","C", "D"],


"B":["E"],
"C":["F","G"],
"D":["H"], Ilustración 5: Distancias de cada nodo con base al nodo inicial
"E":["I"],
"F":["J"]}
El primer grafo se define como un diccionario de listas de
distances = {"A":0} # Inicializa la distancia del nodo de
origen a 0 y de todos los demás a infinito
adyacencia y se muestra en pantalla con la función
printGraph(). A continuación, se ejecuta el algoritmo DFS
La función "recursive_dfs" se llama para el grafo "graph2", desde el nodo '5' y se imprimen los nodos visitados junto con sus
comenzando en el nodo "A", con una lista de nodos vacía y el distancias desde el nodo de inicio.
diccionario "distances".

path, distances = recursive_dfs(graph2, "A", [],


distances)

La función "printGraph2" es similar a la función "printGraph"


pero para el segundo grafo.

#Funcion para dibujar el grafo


def printGraph2(G2, pos, distances):
# positions for all nodes
# nodes
nx.draw_networkx_nodes(G2, pos,
node_size=500,node_color='#8FBC8F')

# edges
nx.draw_networkx_edges(G2, pos,
width=1,arrows=True,arrowsize=20,arrowstyle='->')

# Mostrar las distancias en los nodos


labels = {node: f"{node},{distances[node]}" for node
in G2.nodes()}
nx.draw_networkx_labels(G2, pos, labels,
font_size=10, font_family='cursive')
Ilustración 6: Grafo final "graph"
plt.axis('off')
plt.show() El segundo grafo se define como otro diccionario de listas de
adyacencia. Luego, se ejecuta una implementación recursiva de
DFS desde el nodo "A" en el grafo y se imprimen los nodos

5
BUAP, marzo 2023, Puebla, Puebla MEXICO Fernando Zacarias Flores.

visitados junto con sus distancias desde el nodo de inicio. La REFERENCIAS


función printGraph2() también se utiliza para mostrar el grafo [1] Referencias giga pro
resultante en pantalla. [2]
[3]
[4]
[5]
[6]
[7]
[8]

Ilustración 7: Grafo final "graph2"

En resumen, el código utiliza la biblioteca NetworkX para crear y


visualizar grafos, y también implementa dos algoritmos DFS para
recorrer y encontrar distancias en los grafos.

CONCLUSIONES
En conclusión, el problema de coloreo de grafos es un problema
interesante y desafiante en la teoría de grafos, con aplicaciones
prácticas en el mundo real. Tanto el algoritmo de búsqueda en
profundidad (DFS) como el algoritmo de búsqueda en amplitud
(BFS) son importantes en la solución de este problema y en el
análisis de grafos en general. En Python, hay varias bibliotecas
útiles, como NetworkX y Matplotlib, que permiten la visualización
de grafos y la implementación de algoritmos para resolver el
problema de coloreo de grafos, como se muestra en el código
anterior. Además, la recursión es una herramienta poderosa en la
implementación de DFS, como se puede ver en el segundo ejemplo
de código. En resumen, el problema de coloreo de grafos, junto con
DFS y BFS, son conceptos clave en la teoría de grafos y su
aplicación en el mundo real, y Python ofrece herramientas útiles
para su implementación y visualización.

AGRADECIMIENTOS
Nos gustaría expresar nuestro agradecimiento al profesor Fernando
Zacarías Flores de la Benemérita Universidad Autónoma de Puebla
por impartir este interesante tema. Apreciamos su dedicación y
paciencia para guiarnos a través de los conceptos y ejemplos
prácticos, lo que nos permitió comprender mejor los algoritmos y
sus aplicaciones en la resolución de problemas de grafos. Estamos
agradecidos por su valioso tiempo y experiencia compartida con
nosotros.

También podría gustarte