Fins ara les arestes de Rutalia mesuraven el cost de travessar-les (minuts) o de construir-les (euros de fibra). Aquesta lliçó els dona un tercer significat: capacitat — quants paquets per hora poden circular per cada carrer. La pregunta canvia de naturalesa: ja no busquem el millor camí per a una furgoneta, sinó el cabal màxim que tota la flota pot sostenir entre el magatzem i un barri en hora punta. Aquest és el problema del flux màxim, un dels grans clàssics dels grafs, amb una teoria preciosa (la xarxa residual, el teorema max-flow min-cut) i un abast sorprenent: al final veurem que fins i tot assignar repartidors a comandes és, en secret, un problema de flux.
Contingut
- El problema de flux: capacitats, conservació, font i embornal
- El parany voraç i la xarxa residual: per què calen arestes de retrocés
- Ford-Fulkerson: el mètode dels camins augmentants
- Edmonds-Karp: Ford-Fulkerson amb el BFS de 03-02
- La xarxa d'hora punta de Rutalia, resolta pas a pas
- El teorema max-flow min-cut: el coll d'ampolla físic
- L'assignació com a flux: avançament de 03-06
El problema de flux: capacitats, conservació, font i embornal
Una xarxa de flux és un graf dirigit on cada aresta (u, v) té una capacitat c(u, v) ≥ 0, amb dos nodes distingits: la font s (on el flux neix) i l'embornal t (on mor). Un flux assigna a cada aresta una quantitat f(u, v) complint:
- Restricció de capacitat: 0 ≤ f(u, v) ≤ c(u, v). Per un carrer de 8 paquets/hora no en passen 9.
- Conservació: a tot node llevat de s i t, el que entra és igual al que surt. Les cruïlles no fabriquen ni emmagatzemen paquets.
El valor del flux és el que surt net de s (equivalentment, el que arriba a t). El problema del flux màxim: trobar el flux de valor màxim.
Escenari Rutalia: és hora punta i el Centre Històric (CEN) concentra les comandes. Del Magatzem (ALM) surten paquets cap a CEN a través de la zona del Mercat (MER), el Pont del Riu (RIO) i la Ciutat Universitària (UNI). Les capacitats (paquets/hora, estimades per trànsit i nombre de furgonetes que admet cada eix, en el sentit útil de l'hora punta) són:
graph LR
ALM((ALM font)) -->|12| MER((MER))
ALM -->|11| RIO((RIO))
RIO -->|4| MER
MER -->|7| UNI((UNI))
MER -->|6| CEN((CEN embornal))
RIO -->|9| CEN
UNI -->|8| CEN
Pregunta: quants paquets/hora pot injectar Rutalia al Centre? A ull no és obvi: d'ALM en surten 12 + 11 = 23, a CEN n'entren 6 + 9 + 8 = 23… però veurem que la resposta real és 22, i que el límit no és ni a la sortida ni a l'arribada, sinó en un tall intermedi.
El parany voraç i la xarxa residual: per què calen arestes de retrocés
Primer impuls: buscar un camí de s a t amb capacitat lliure, enviar-hi tot el possible, repetir. El problema és que una elecció primerenca pot bloquejar combinacions millors. Exemple mínim (subxarxa amb capacitats petites per veure-ho clar):
- ALM→MER: 8, ALM→RIO: 8, MER→CEN: 8, RIO→CEN: 8 i una drecera transversal MER→RIO: 6.
- L'òptim és obvi: 8 per dalt (ALM→MER→CEN) i 8 per baix (ALM→RIO→CEN) = 16, ignorant la drecera.
- Però suposa que el primer camí explorat és ALM→MER→RIO→CEN i hi enviem 6. Ara ALM→MER té 2 de lliures i RIO→CEN en té 2 de lliures: els camins directes només aporten 2 + 2 = 4 més. Total 10. Encallats lluny de 16.
La solució és comptable, no física: permetre desfer decisions. Es defineix la xarxa residual: per a cada aresta amb capacitat c i flux f, la residual conté:
- l'aresta cap endavant amb capacitat c − f (el que encara hi cap), i
- una aresta de retrocés v→u amb capacitat f (el que es pot cancel·lar).
A l'exemple encallat, la xarxa residual conté RIO→MER amb capacitat 6 (retrocés de la drecera). El camí residual ALM→RIO→MER→CEN amb coll 6 "hi envia 6" que en realitat significa: 6 unitats noves entren per baix fins a RIO, i 6 de les que giraven per la drecera cap a RIO es queden a dalt i segueixen cap a CEN. Ningú no circula marxa enrere: només es reescriu la comptabilitat. Total: 16. L'avarícia inicial, corregida sense començar de zero.
Un camí de s a t a la xarxa residual s'anomena camí augmentant; el seu coll d'ampolla és la capacitat residual mínima de les seves arestes.
Ford-Fulkerson: el mètode dels camins augmentants
El mètode de Ford-Fulkerson és exactament aquest bucle:
mentre existeixi un cami augmentant s -> t a la xarxa residual fer
enviar-hi tantes unitats com permeti el seu coll d'ampolla
actualitzar la xarxa residual (restar cap endavant, sumar retrocessos)
retornar el flux acumulatPropietats clau:
- Amb capacitats enteres, cada iteració augmenta el flux en ≥ 1, per tant acaba; i el flux màxim resultant és enter (teorema d'integralitat — serà crucial a 03-06: "mig repartidor" no existeix).
- Cost: O(m) per iteració de cerca × nombre d'iteracions. Si els camins es trien malament, les iteracions poden ser fins a f* (el valor del flux màxim): O(m · f*). Existeix un exemple clàssic amb capacitats 1.000.000 i una drecera de capacitat 1 on una elecció perversa alterna 2 milions de caminets d'1 unitat. "Ford-Fulkerson" és un mètode; falta fixar com es busca el camí.
Edmonds-Karp: Ford-Fulkerson amb el BFS de 03-02
Edmonds-Karp concreta l'elecció: buscar sempre el camí augmentant amb menys arestes, és a dir, amb el BFS de 03-02 sobre la xarxa residual. Aquest detall fita les iteracions en O(n·m) independentment de les capacitats, donant un cost total de O(n · m²).
from collections import deque
def edmonds_karp(cap, s, t):
"""cap: {u: {v: capacitat}} DIRIGIT. Retorna (flux_max, flux, S_del_tall)."""
# Xarxa residual com a dict imbricat; inclou retrocessos inicialitzats a 0
res = {u: {} for u in cap}
for u in cap:
for v, c in cap[u].items():
res[u][v] = res[u].get(v, 0) + c
res.setdefault(v, {}).setdefault(u, 0) # aresta de retroces
flux_max = 0
while True:
# BFS a la xarxa residual usant nomes arestes amb capacitat restant
pare = {s: None}
cua = deque([s])
while cua and t not in pare:
u = cua.popleft()
for v, c_res in res[u].items():
if v not in pare and c_res > 0:
pare[v] = u
cua.append(v)
if t not in pare: # no hi ha cami augmentant: fi
S = set(pare) # abastables a la residual
return flux_max, res, S
# coll d'ampolla del cami trobat
coll, v = float("inf"), t
while pare[v] is not None:
u = pare[v]
coll = min(coll, res[u][v])
v = u
# actualitzar la xarxa residual al llarg del cami
v = t
while pare[v] is not None:
u = pare[v]
res[u][v] -= coll # menys marge cap endavant
res[v][u] += coll # mes marge de cancellacio
v = u
flux_max += collLectura guiada del codi:
- La xarxa residual
resunifica marge i retrocés:res[u][v]és "quant més puc empènyer d'u a v ara mateix", tant si (u,v) era una aresta real com si és l'ombra d'una aresta contrària. - El BFS és literalment el de 03-02 amb un filtre extra (
c_res > 0) i aturada primerenca en abastar t;parereconstrueix el camí igual que aleshores. - Quan no hi ha camí, el conjunt
pare(els abastables des de s a la residual) no és un subproducte: és la meitat S del tall mínim, com veurem de seguida. L'algorisme regala el certificat d'optimalitat.
La xarxa d'hora punta de Rutalia, resolta pas a pas
HORA_PUNTA = {
"ALM": {"MER": 12, "RIO": 11},
"MER": {"UNI": 7, "CEN": 6},
"RIO": {"MER": 4, "CEN": 9},
"UNI": {"CEN": 8},
"CEN": {},
}
f, res, S = edmonds_karp(HORA_PUNTA, "ALM", "CEN")
print(f) # 22
print(S) # {'ALM', 'RIO', 'MER'}Seqüència de camins augmentants que troba Edmonds-Karp (BFS prioritza els curts):
| Iteració | Camí augmentant | Coll | Flux acumulat |
|---|---|---|---|
| 1 | ALM→MER→CEN | 6 | 6 |
| 2 | ALM→RIO→CEN | 9 | 15 |
| 3 | ALM→MER→UNI→CEN | 6 | 21 |
| 4 | ALM→RIO→MER→UNI→CEN | 1 | 22 |
| 5 | (el BFS no arriba a CEN) | — | 22 |
El flux final per aresta: ALM→MER 12/12, ALM→RIO 10/11, RIO→MER 1/4, MER→CEN 6/6, MER→UNI 7/7, RIO→CEN 9/9, UNI→CEN 7/8. Comprova la conservació a MER: entren 12 + 1 = 13, surten 6 + 7 = 13 ✓. La iteració 4 és la xarxa residual en acció: el paquet extra entra pel riu i usa la drecera RIO→MER per abastar el marge que quedava a UNI→CEN.
El teorema max-flow min-cut: el coll d'ampolla físic
Un tall s-t és una partició dels nodes en (S, T) amb s ∈ S i t ∈ T; la seva capacitat és la suma de capacitats de les arestes que van de S a T (només aquest sentit). Tot flux ha de travessar qualsevol tall; per tant, flux màxim ≤ capacitat de qualsevol tall. El resultat profund és la igualtat:
Teorema max-flow min-cut: el valor del flux màxim és exactament la capacitat del tall mínim.
I la demostració és constructiva amb el que ja tenim: quan Edmonds-Karp s'atura, S = {abastables des de s a la residual} defineix un tall les arestes S→T del qual estan totes saturades (si tinguessin marge, el BFS hauria creuat). Aquell tall té capacitat = flux actual, i com que cap flux no supera cap tall, tots dos són òptims alhora. L'algorisme no només dona el número: dona el certificat, igual que la fita del B&B a 02-03 certificava el 35,22 del TSP.
A Rutalia: S = {ALM, RIO, MER}, T = {UNI, CEN}. Les arestes del tall mínim són MER→UNI (7), MER→CEN (6) i RIO→CEN (9): 7 + 6 + 9 = 22. Interpretació física immediata per a l'equip d'operacions:
- El límit de 22 paquets/hora no és a la sortida del magatzem (23) ni als accessos finals al Centre (23), sinó a l'anell intermedi.
- Si l'ajuntament pregunta quins carrers ampliar, la resposta del teorema és quirúrgica: només els del tall mínim. Ampliar ALM→MER o UNI→CEN no afegeix ni un paquet; ampliar RIO→CEN en 1 puja el cabal a 23 (fins que un altre tall passi a ser el mínim — recalcula després de cada canvi).
Fixa't en el paral·lelisme amb 03-02: allà preguntàvem si un tall desconnecta (connectivitat); aquí, quant estrangula (capacitat). El flux màxim és la versió quantitativa de la robustesa.
L'assignació com a flux: avançament de 03-06
La sorpresa final: el flux màxim resol problemes on no hi ha res que "flueixi". Es poden assignar 3 repartidors a 3 comandes si cada repartidor només pot atendre certes comandes (per zona, per tipus de vehicle)? Construïm aquesta xarxa:
- Font s → cada repartidor, capacitat 1 (cadascú atén com a molt una comanda).
- Repartidor → cada comanda compatible, capacitat 1.
- Cada comanda → embornal t, capacitat 1 (cada comanda la serveix com a molt un).
Cada unitat de flux entera és una parella repartidor-comanda, i el flux màxim és el nombre màxim d'assignacions compatibles simultànies. La integralitat de Ford-Fulkerson garanteix que la solució no parteix repartidors en fraccions. Aquesta reducció —convertir un problema en un altre de ja resolt— és una de les armes més elegants de l'algorísmica, i és exactament el pont cap a la propera lliçó: l'aparellament en grafs bipartits (03-06), on la desenvoluparem amb tot detall i amb els seus algorismes especialitzats.
Errors Comuns i Consells
- Ometre les arestes de retrocés: l'error número u. Sense elles, el resultat depèn de l'ordre d'exploració i pot quedar-se curt (10 davant de 16 al nostre exemple mínim). Si el teu "flux màxim" canvia en reordenar veïns, gairebé segur que és això.
- Modelar la xarxa com a no dirigida: les capacitats d'hora punta tenen sentit — un carrer de doble sentit es modela com dues arestes dirigides, cadascuna amb la seva capacitat. Copiar el graf de 03-01 sense dirigir-lo produeix respostes sense significat.
- Usar DFS per al camí augmentant amb capacitats grans: Ford-Fulkerson pur pot iterar milions de vegades (l'exemple de la drecera de capacitat 1). El BFS d'Edmonds-Karp fita les iteracions sense dependre de les capacitats. Per a xarxes serioses hi ha algorismes millors (Dinic, push-relabel);
networkx.maximum_flowels porta de sèrie. - Llegir el tall mínim com "les arestes saturades": hi ha arestes saturades que no són al tall mínim (ALM→MER va a 12/12 i no hi és). El tall és S→T amb S = abastables a la residual; la saturació és necessària però no suficient.
- Oblidar verificar la conservació en depurar: suma entrades i sortides de cada node intermedi. És l'
assertmés barat i delator de tota aquesta lliçó. - Consell: dibuixa sempre la xarxa residual després de cada augment en exemples petits. El moment "aha" d'aquesta lliçó és veure com un retrocés converteix una mala decisió en reversible.
Exercicis
- Ampliació quirúrgica. Usant
edmonds_karp, comprova quant millora el cabal de la xarxa d'hora punta si (a) ALM→MER passa de 12 a 15, (b) RIO→CEN passa de 9 a 11. Explica tots dos resultats amb el tall mínim abans d'executar el codi, i verifica-ho. - El pitjor tall de l'analista. Calcula a mà la capacitat dels talls S = {ALM} i S = {ALM, MER, RIO, UNI} de la xarxa d'hora punta i comprova que tots dos superen 22. Què et diu això sobre usar "el que surt del magatzem" com a estimació de la capacitat de repartiment?
- Assignació exprés. Rutalia té 3 repartidors amb compatibilitats: R1→{P1, P2}, R2→{P2}, R3→{P2, P3}. Munta la xarxa d'assignació (font, embornal, capacitats 1) i calcula amb
edmonds_karpquantes comandes poden servir-se alhora. Hi ha assignació perfecta?
Solucions
Exercici 1:
xarxa_a = {u: dict(vs) for u, vs in HORA_PUNTA.items()}
xarxa_a["ALM"]["MER"] = 15
print(edmonds_karp(xarxa_a, "ALM", "CEN")[0]) # 22 -> no millora res
xarxa_b = {u: dict(vs) for u, vs in HORA_PUNTA.items()}
xarxa_b["RIO"]["CEN"] = 11
print(edmonds_karp(xarxa_b, "ALM", "CEN")[0]) # 23 -> +1 (no +2)(a) ALM→MER no pertany al tall mínim {MER→UNI, MER→CEN, RIO→CEN}: ampliar-la és llençar els diners, l'estrangulament segueix aigües avall. (b) RIO→CEN sí que és al tall: ampliar en 2 puja el tall a 24, però aleshores mana un altre límit (amb 23 se satura la sortida ALM: 12+11) i només es guanya 1. Els talls es rellevan: després de cada obra cal recalcular.
Exercici 2:
- S = {ALM}: arestes ALM→MER (12) + ALM→RIO (11) = 23.
- S = {ALM, MER, RIO, UNI}: arestes cap a T = {CEN}: MER→CEN (6) + RIO→CEN (9) + UNI→CEN (8) = 23.
Tots dos talls valen 23 > 22: són fites superiors vàlides però no ajustades. Moralitat: la capacitat de sortida del magatzem (o d'entrada al barri) és una estimació optimista del cabal real; el veritable límit pot amagar-se en qualsevol tall intermedi, i només el flux màxim el troba amb certificat.
Exercici 3:
ASSIGNACIO = {
"s": {"R1": 1, "R2": 1, "R3": 1},
"R1": {"P1": 1, "P2": 1},
"R2": {"P2": 1},
"R3": {"P2": 1, "P3": 1},
"P1": {"t": 1}, "P2": {"t": 1}, "P3": {"t": 1},
"t": {},
}
print(edmonds_karp(ASSIGNACIO, "s", "t")[0]) # 3Flux màxim 3 = assignació perfecta: R1→P1, R2→P2, R3→P3. Fixa't que la voracitat ingènua podia fallar (si R1 prengués P2, R2 quedava sense comanda) i és la maquinària de camins augmentants la que ho redreça — a 03-06 veurem aquesta mateixa correcció amb el seu nom propi: camí alternant.
Conclusió
Hem afegit la tercera lectura d'una aresta —capacitat— i amb ella el problema del flux màxim: cabal de s a t respectant capacitats i conservació. La peça conceptual clau és la xarxa residual, les arestes de retrocés de la qual converteixen les decisions voraces en reversibles i sostenen el mètode de Ford-Fulkerson; la concreció pràctica és Edmonds-Karp, que busca cada camí augmentant amb el BFS de 03-02 i garanteix O(n·m²). I el premi teòric és max-flow min-cut: el flux màxim de l'hora punta de Rutalia és de 22 paquets/hora no pas pel que surt del magatzem ni pel que cap al Centre, sinó per un tall intermedi de tres carrers — el coll d'ampolla físic que diu exactament què ampliar i què no. De regal, una reducció amb futur immediat: l'assignació repartidor-comanda és un flux amb capacitats 1. A 03-06, última lliçó del mòdul, aquesta idea floreix en els algorismes d'aparellament en grafs bipartits: bipartició, camins alternants, l'algorisme hongarès i l'assignació òptima que a 02-01 resolíem amb programació lineal.
Algorismes Avançats
Mòdul 1: Introducció als Algorismes Avançats
- Conceptes Bàsics i Notació
- Anàlisi de Complexitat
- Recursió i Programació Dinàmica
- Estructures de Dades Avançades
Mòdul 2: Algorismes d'Optimització
- Programació Lineal
- Algorismes d'Optimització Combinatòria
- Backtracking i Branch and Bound
- Algorismes Genètics
- Optimització de Colònia de Formigues
Mòdul 3: Algorismes en Grafs
- Representació de Grafs
- Cerca en Grafs: BFS i DFS
- Algorismes de Camins Mínims
- Arbres d'Expansió Mínima
- Algorismes de Flux Màxim
- Algorismes d'Aparellament en Grafs
Mòdul 4: Algorismes de Cerca i Ordenació
Mòdul 5: Algorismes d'Aprenentatge Automàtic
- Introducció a l'Aprenentatge Automàtic
- Algorismes de Classificació
- Algorismes de Regressió
- Xarxes Neuronals i Deep Learning
- Algorismes de Clustering
Mòdul 6: Casos d'Estudi i Aplicacions
- Optimització a la Indústria
- Aplicacions de Grafs a les Xarxes Socials
- Cerca i Ordenació en Grans Volums de Dades
- Aplicacions d'Aprenentatge Automàtic a la Vida Real
