BFS (breadth-first search) recorre el grafo en rondas: arranca en un vértice, usa una cola y visita primero sus vecinos, luego los vecinos de ellos, y así hasta cubrir todo. En grafos sin pesos garantiza llegar en la menor cantidad de aristas y registra quién descubrió a cada nodo para armar el camino.
Partimos de un origen, lo marcamos como visitado y lo encolamos. Luego, repetimos: desencolar un vértice, procesar sus vecinos no visitados, marcarlos y encolarlos. Se avanza capa por capa.
Usamos deque para mantener O(1) por operación.
from collections import deque
cola = deque()
cola.append(0)
v = cola.popleft()
visitado en False.u, visitar vecinos v no marcados, marcarlos y encolarlos.v si se necesita reconstruir caminos.from collections import deque
def bfs_matriz(matriz, origen):
n = len(matriz)
visitado = [False] * n
cola = deque([origen])
visitado[origen] = True
while cola:
u = cola.popleft()
print(u, end=" ")
for v in range(n):
if matriz[u][v] != 0 and not visitado[v]:
visitado[v] = True
cola.append(v)
from collections import deque
def bfs_lista(g, origen):
visitado = {v: False for v in g}
cola = deque([origen])
visitado[origen] = True
while cola:
u = cola.popleft()
print(u, end=" ")
for v, _ in g[u]:
if not visitado[v]:
visitado[v] = True
cola.append(v)
Para reconstruir caminos mínimos, guarda un diccionario padre y asigna padre[v] = u cuando se encola v desde u. Al finalizar, padre define el árbol de BFS.
from collections import deque
def bfs_con_padres(g, origen):
visitado = {v: False for v in g}
padre = {v: None for v in g}
cola = deque([origen])
visitado[origen] = True
while cola:
u = cola.popleft()
for v, _ in g[u]:
if not visitado[v]:
visitado[v] = True
padre[v] = u
cola.append(v)
return padre
Con padre poblado, reconstruye un camino desde cualquier destino siguiendo padres hasta llegar al origen. El siguiente fragmento arma el camino en orden origen a destino:
def reconstruir_camino(padre, origen, destino):
camino = []
actual = destino
while actual is not None:
camino.append(actual)
if actual == origen:
break
actual = padre[actual]
if not camino or camino[-1] != origen:
print(f"No hay camino de {origen} a {destino}")
return
camino.reverse()
print(f"Camino {origen} -> {destino}: " + " -> ".join(map(str, camino)))
Programa autocontenido que construye un grafo, ejecuta BFS y muestra el árbol de padres.
from collections import deque
def bfs_con_padres(g, origen):
visitado = {v: False for v in g}
padre = {v: None for v in g}
cola = deque([origen])
visitado[origen] = True
while cola:
u = cola.popleft()
for v, _ in g[u]:
if not visitado[v]:
visitado[v] = True
padre[v] = u
cola.append(v)
return padre
def reconstruir_camino(padre, origen, destino):
camino = []
actual = destino
while actual is not None:
camino.append(actual)
if actual == origen:
break
actual = padre[actual]
if not camino or camino[-1] != origen:
print(f"No hay camino de {origen} a {destino}")
return
camino.reverse()
print(f"Camino {origen} -> {destino}: " + " -> ".join(map(str, camino)))
def main():
g = {
0: [(1, 1), (2, 1)],
1: [(0, 1), (3, 1)],
2: [(0, 1), (3, 1)],
3: [(1, 1), (2, 1), (4, 1)],
4: [(3, 1)]
}
padre = bfs_con_padres(g, 0)
print("Padres en el arbol BFS desde 0:")
for v in sorted(padre.keys()):
print(f"{v} -> {padre[v] if padre[v] is not None else -1}")
reconstruir_camino(padre, 0, 4)
if __name__ == "__main__":
main()
Ejecuta el programa para ver cómo se forma el árbol de BFS y modifica las aristas para probar distintas topologías. Con la configuración incluida, la salida esperada es:
Padres en el arbol BFS desde 0:
0 -> -1
1 -> 0
2 -> 0
3 -> 1
4 -> 3
Camino 0 -> 4: 0 -> 1 -> 3 -> 4