Els algoritmes de flux màxim són fonamentals en la teoria de grafs i tenen aplicacions en una àmplia varietat de camps, com ara la logística, les xarxes de comunicació, la planificació de projectes i molts altres. En aquesta secció, explorarem els conceptes bàsics del flux màxim, els algoritmes més utilitzats per trobar el flux màxim en un graf i alguns exemples pràctics.
Conceptes Bàsics
Abans d'entrar en els algoritmes, és important entendre alguns conceptes clau relacionats amb el flux màxim:
- Graf Dirigit: Un graf on les arestes tenen una direcció associada.
- Capacitat: Cada aresta del graf té una capacitat que indica el màxim flux que pot transportar.
- Font (s): El node d'on surt el flux.
- Destí (t): El node on arriba el flux.
- Flux: La quantitat de "càrrega" que es mou des de la font fins al destí a través de les arestes del graf.
- Camí Augmentant: Un camí des de la font fins al destí on es pot augmentar el flux.
Algoritmes Principals
Algoritme de Ford-Fulkerson
L'algoritme de Ford-Fulkerson és un dels més coneguts per trobar el flux màxim en un graf. Funciona de la següent manera:
- Inicialització: Comença amb un flux inicial de 0.
- Cerca de Camins Augmentants: Busca un camí augmentant des de la font fins al destí.
- Augment del Flux: Augmenta el flux al llarg del camí augmentant trobat.
- Repetició: Repeteix els passos 2 i 3 fins que no es puguin trobar més camins augmentants.
Exemple de Codi
from collections import defaultdict class Graph: def __init__(self, vertices): self.graph = defaultdict(list) self.ROW = vertices def add_edge(self, u, v, w): self.graph[u].append((v, w)) def bfs(self, s, t, parent): visited = [False] * self.ROW queue = [] queue.append(s) visited[s] = True while queue: u = queue.pop(0) for ind, val in enumerate(self.graph[u]): v, w = val if visited[v] == False and w > 0: queue.append(v) visited[v] = True parent[v] = u return True if visited[t] else False def ford_fulkerson(self, source, sink): parent = [-1] * self.ROW max_flow = 0 while self.bfs(source, sink, parent): path_flow = float("Inf") s = sink while s != source: for v, w in self.graph[parent[s]]: if v == s: path_flow = min(path_flow, w) s = parent[s] max_flow += path_flow v = sink while v != source: u = parent[v] for i, (vertex, weight) in enumerate(self.graph[u]): if vertex == v: self.graph[u][i] = (vertex, weight - path_flow) for i, (vertex, weight) in enumerate(self.graph[v]): if vertex == u: self.graph[v][i] = (vertex, weight + path_flow) v = parent[v] return max_flow # Exemple d'ús g = Graph(6) g.add_edge(0, 1, 16) g.add_edge(0, 2, 13) g.add_edge(1, 2, 10) g.add_edge(1, 3, 12) g.add_edge(2, 1, 4) g.add_edge(2, 4, 14) g.add_edge(3, 2, 9) g.add_edge(3, 5, 20) g.add_edge(4, 3, 7) g.add_edge(4, 5, 4) source = 0 sink = 5 print("El flux màxim és %d" % g.ford_fulkerson(source, sink))
Algoritme d'Edmonds-Karp
L'algoritme d'Edmonds-Karp és una implementació específica de l'algoritme de Ford-Fulkerson que utilitza una cerca en amplada (BFS) per trobar camins augmentants. Això garanteix una complexitat temporal de \(O(VE^2)\), on \(V\) és el nombre de vèrtexs i \(E\) és el nombre d'arestes.
Algoritme de Push-Relabel
Aquest algoritme és una alternativa als anteriors i es basa en la idea de "empenyiment" (push) i "relabeling" (relabel). Funciona de la següent manera:
- Inicialització: Assigna un excés de flux a cada node.
- Empenyiment: Mou el flux des d'un node amb excés a un node adjacent.
- Relabel: Augmenta l'altura d'un node per permetre més moviments de flux.
Aquest algoritme té una complexitat temporal de \(O(V^2E)\).
Exercicis Pràctics
Exercici 1: Implementació de l'Algoritme de Ford-Fulkerson
Implementa l'algoritme de Ford-Fulkerson per trobar el flux màxim en un graf donat. Utilitza el següent graf com a exemple:
Nodes: 0, 1, 2, 3, 4, 5 Arestes: (0, 1, 10), (0, 2, 5), (1, 2, 15), (1, 3, 10), (2, 4, 10), (3, 4, 10), (3, 5, 10), (4, 5, 10)
Solució
# Implementació de l'algoritme de Ford-Fulkerson g = Graph(6) g.add_edge(0, 1, 10) g.add_edge(0, 2, 5) g.add_edge(1, 2, 15) g.add_edge(1, 3, 10) g.add_edge(2, 4, 10) g.add_edge(3, 4, 10) g.add_edge(3, 5, 10) g.add_edge(4, 5, 10) source = 0 sink = 5 print("El flux màxim és %d" % g.ford_fulkerson(source, sink))
Exercici 2: Comparació d'Algoritmes
Implementa tant l'algoritme de Ford-Fulkerson com l'algoritme d'Edmonds-Karp i compara el temps d'execució per a diferents grafs.
Solució
import time # Implementació de l'algoritme d'Edmonds-Karp class GraphEdmondsKarp(Graph): def bfs(self, s, t, parent): visited = [False] * self.ROW queue = [] queue.append(s) visited[s] = True while queue: u = queue.pop(0) for ind, val in enumerate(self.graph[u]): v, w = val if visited[v] == False and w > 0: queue.append(v) visited[v] = True parent[v] = u return True if visited[t] else False def edmonds_karp(self, source, sink): parent = [-1] * self.ROW max_flow = 0 while self.bfs(source, sink, parent): path_flow = float("Inf") s = sink while s != source: for v, w in self.graph[parent[s]]: if v == s: path_flow = min(path_flow, w) s = parent[s] max_flow += path_flow v = sink while v != source: u = parent[v] for i, (vertex, weight) in enumerate(self.graph[u]): if vertex == v: self.graph[u][i] = (vertex, weight - path_flow) for i, (vertex, weight) in enumerate(self.graph[v]): if vertex == u: self.graph[v][i] = (vertex, weight + path_flow) v = parent[v] return max_flow # Comparació de temps d'execució g = Graph(6) g.add_edge(0, 1, 10) g.add_edge(0, 2, 5) g.add_edge(1, 2, 15) g.add_edge(1, 3, 10) g.add_edge(2, 4, 10) g.add_edge(3, 4, 10) g.add_edge(3, 5, 10) g.add_edge(4, 5, 10) source = 0 sink = 5 start_time = time.time() print("El flux màxim amb Ford-Fulkerson és %d" % g.ford_fulkerson(source, sink)) print("Temps d'execució: %s segons" % (time.time() - start_time)) g_ek = GraphEdmondsKarp(6) g_ek.add_edge(0, 1, 10) g_ek.add_edge(0, 2, 5) g_ek.add_edge(1, 2, 15) g_ek.add_edge(1, 3, 10) g_ek.add_edge(2, 4, 10) g_ek.add_edge(3, 4, 10) g_ek.add_edge(3, 5, 10) g_ek.add_edge(4, 5, 10) start_time = time.time() print("El flux màxim amb Edmonds-Karp és %d" % g_ek.edmonds_karp(source, sink)) print("Temps d'execució: %s segons" % (time.time() - start_time))
Conclusió
En aquesta secció, hem explorat els conceptes bàsics del flux màxim, així com els algoritmes més utilitzats per trobar el flux màxim en un graf. Hem vist com implementar l'algoritme de Ford-Fulkerson i l'algoritme d'Edmonds-Karp, i hem comparat els seus temps d'execució. Amb aquests coneixements, estàs preparat per abordar problemes complexos de flux en grafs i aplicar aquests algoritmes en situacions reals.
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