Introducció
En aquest tema, explorarem dos dels algorismes més fonamentals per a la cerca en grafs: la Cerca en Amplada (BFS) i la Cerca en Profunditat (DFS). Aquests algorismes són essencials per a moltes aplicacions en informàtica, incloent la navegació de xarxes, la resolució de puzles i la cerca de camins en mapes.
Conceptes Clau
Graf
Un graf és una estructura composta per nodes (o vèrtexs) i arestes que connecten aquests nodes. Els grafs poden ser dirigits o no dirigits, ponderats o no ponderats.
BFS (Breadth-First Search)
La Cerca en Amplada explora els nodes d'un graf nivell per nivell. És a dir, primer visita tots els nodes a una distància de 1 del node inicial, després tots els nodes a una distància de 2, i així successivament.
DFS (Depth-First Search)
La Cerca en Profunditat explora tan profundament com sigui possible al llarg de cada branca abans de retrocedir. Això significa que segueix un camí fins arribar al final abans de tornar enrere i explorar altres camins.
Algorisme BFS
Pseudocodi
BFS(Graf G, Node inicial s): Crear una cua Q Marcar s com visitat i afegir-lo a Q mentre Q no estigui buida: u = Q.desencuar() per cada veí v de u: si v no ha estat visitat: marcar v com visitat afegir v a Q
Implementació en Python
from collections import deque def bfs(graph, start): visited = set() queue = deque([start]) visited.add(start) while queue: vertex = queue.popleft() print(vertex, end=" ") for neighbor in graph[vertex]: if neighbor not in visited: visited.add(neighbor) queue.append(neighbor) # Exemple de graf graph = { 'A': ['B', 'C'], 'B': ['A', 'D', 'E'], 'C': ['A', 'F'], 'D': ['B'], 'E': ['B', 'F'], 'F': ['C', 'E'] } bfs(graph, 'A')
Explicació del Codi
- Utilitzem una cua (
deque
) per mantenir els nodes a visitar. - Afegim el node inicial a la cua i el marquem com visitat.
- Mentre la cua no estigui buida, desencuem un node, el processem i afegim els seus veïns no visitats a la cua.
Algorisme DFS
Pseudocodi
DFS(Graf G, Node inicial s): Crear una pila S Marcar s com visitat i afegir-lo a S mentre S no estigui buida: u = S.desapilar() per cada veí v de u: si v no ha estat visitat: marcar v com visitat afegir v a S
Implementació en Python
def dfs(graph, start): visited = set() stack = [start] while stack: vertex = stack.pop() if vertex not in visited: print(vertex, end=" ") visited.add(vertex) stack.extend(set(graph[vertex]) - visited) # Exemple de graf graph = { 'A': ['B', 'C'], 'B': ['A', 'D', 'E'], 'C': ['A', 'F'], 'D': ['B'], 'E': ['B', 'F'], 'F': ['C', 'E'] } dfs(graph, 'A')
Explicació del Codi
- Utilitzem una pila per mantenir els nodes a visitar.
- Afegim el node inicial a la pila.
- Mentre la pila no estigui buida, desapilem un node, el processem i afegim els seus veïns no visitats a la pila.
Comparació entre BFS i DFS
Característica | BFS | DFS |
---|---|---|
Estructura de Dades | Cua | Pila |
Estratègia | Nivell per nivell | Profunditat màxima primer |
Ús típic | Camins més curts en grafs no ponderats | Exploració completa, resolució de puzles |
Complexitat Temporal | O(V + E) | O(V + E) |
Complexitat Espacial | O(V) | O(V) |
Exercicis Pràctics
Exercici 1: Implementació de BFS
Implementa l'algorisme BFS per a un graf dirigit i troba el camí més curt des d'un node inicial a tots els altres nodes.
Exercici 2: Implementació de DFS
Implementa l'algorisme DFS per a un graf no dirigit i determina si el graf és connex.
Exercici 3: Aplicació de BFS i DFS
Utilitza BFS i DFS per trobar tots els components connexos en un graf no dirigit.
Solucions
Solució a l'Exercici 1
def bfs_shortest_path(graph, start): visited = {start: None} queue = deque([start]) while queue: vertex = queue.popleft() for neighbor in graph[vertex]: if neighbor not in visited: visited[neighbor] = vertex queue.append(neighbor) return visited # Exemple de graf dirigit graph = { 'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': [] } print(bfs_shortest_path(graph, 'A'))
Solució a l'Exercici 2
def dfs_connected(graph, start, visited=None): if visited is None: visited = set() visited.add(start) for neighbor in graph[start]: if neighbor not in visited: dfs_connected(graph, neighbor, visited) return visited # Exemple de graf no dirigit graph = { 'A': ['B', 'C'], 'B': ['A', 'D', 'E'], 'C': ['A', 'F'], 'D': ['B'], 'E': ['B', 'F'], 'F': ['C', 'E'] } print(dfs_connected(graph, 'A'))
Solució a l'Exercici 3
def find_connected_components(graph): visited = set() components = [] for vertex in graph: if vertex not in visited: component = dfs_connected(graph, vertex) components.append(component) visited.update(component) return components # Exemple de graf no dirigit amb múltiples components graph = { 'A': ['B'], 'B': ['A'], 'C': ['D'], 'D': ['C'], 'E': [] } print(find_connected_components(graph))
Resum
En aquesta secció, hem après sobre dos algorismes fonamentals per a la cerca en grafs: BFS i DFS. Hem vist com implementar-los en Python i hem explorat les seves aplicacions i diferències. Aquests algorismes són eines essencials per a molts problemes computacionals i són la base per a tècniques més avançades en el camp dels grafs.
Algoritmes Avançats
Mòdul 1: Introducció als Algoritmes Avançats
Mòdul 2: Algoritmes d'Optimització
- Programació Lineal
- Algoritmes d'Optimització Combinatòria
- Algoritmes Genètics
- Optimització de Colònia de Formigues
Mòdul 3: Algoritmes en Grafs
- Representació de Grafs
- Cerca en Grafs: BFS i DFS
- Algoritmes de Camins Mínims
- Algoritmes de Flux Màxim
- Algoritmes d'Aparellament en Grafs
Mòdul 4: Algoritmes de Cerca i Ordenació
Mòdul 5: Algoritmes d'Aprenentatge Automàtic
- Introducció a l'Aprenentatge Automàtic
- Algoritmes de Classificació
- Algoritmes de Regressió
- Xarxes Neuronals i Deep Learning
- Algoritmes de Clustering
Mòdul 6: Casos d'Estudi i Aplicacions
- Optimització en la Indústria
- Aplicacions de Grafs en Xarxes Socials
- Cerca i Ordenació en Grans Volums de Dades
- Aplicacions d'Aprenentatge Automàtic en la Vida Real