Referencia de los algoritmos
Pseudocódigo, invariantes y errores comunes de cada método del estudio, con la misma notación usada en clase. Es exactamente esta formulación la que la simulación ejecuta paso a paso.
Búsqueda en grafos
Búsqueda en profundidad
Elige siempre el vértice marcado alcanzado más recientemente y registra un tiempo de descubrimiento TD y un tiempo de finalización TF.
Idea central
Búsqueda genérica en la que, entre todos los vértices marcados e incidentes a alguna arista aún no explorada, se elige siempre el alcanzado más recientemente. Cada vértice recibe un tiempo de descubrimiento TD[v] y un tiempo de finalización TF[v], marcados por un contador global t.
Invariante
Los intervalos de vida I(v) = [TD[v], TF[v]] están anidados o son disjuntos; nunca se superponen parcialmente. El vértice w es descendiente de v si y solo si I(w) está contenido en I(v).
Requisitos del grafo
Errores comunes
- En un grafo no dirigido solo existen aristas de árbol y de retroceso; las de avance y de cruce solo aparecen en grafos dirigidos.
- Olvidar la condición w ≠ padre[v]: la arista usada para llegar a v no es una arista de retroceso.
- Toda arista de retroceso revela un ciclo en el grafo original. En un grafo dirigido, es la única evidencia necesaria.
Inicialización / Llamada inicialt ← 0para todo vértice v ∈ V(G) hacerTD[v] ← 0; TF[v] ← 0; padre[v] ← nulomientras exista algún vértice v tal que TD[v] = 0 hacerEjecutar Búsqueda_Profundidad(v) // v es la raíz de la búsquedaBúsqueda_Profundidad(v) // grafo no dirigidot ← t + 1; TD[v] ← tpara todo vértice w ∈ Γ(v) hacersi TD[w] = 0 entonces // arista de árbolpadre[w] ← v; Ejecutar Búsqueda_Profundidad(w)si no, si TF[w] = 0 y w ≠ padre[v] entoncesVisitar arista de retroceso {v, w}t ← t + 1; TF[v] ← tBúsqueda_Profundidad(v) // grafo dirigidopara todo vértice w ∈ Γ⁺(v) hacersi TD[w] = 0 entonces arista de árbol (v, w); padre[w] ← v; ...si no, si TF[w] = 0 entonces arista de retroceso (v, w)si no, si TD[v] < TD[w] entonces arista de avance (v, w)si no arista de cruce (v, w)
Búsqueda en grafos
Búsqueda en anchura
Elige siempre el vértice marcado alcanzado hace más tiempo, usando una cola, y asigna a cada vértice su nivel.
Idea central
Búsqueda genérica en la que, entre todos los vértices marcados e incidentes a alguna arista aún no explorada, se elige siempre el alcanzado hace más tiempo, criterio que se implementa con una cola. Cada vértice recibe un índice L[v] (orden de descubrimiento) y un nivel[v] (distancia a la raíz en número de aristas).
Invariante
nivel[w] = nivel[padre[w]] + 1 para todo w ≠ raíz. Así, en el momento en que w se marca, nivel[w] ya es la distancia (número de aristas) entre la raíz de la búsqueda y w.
Requisitos del grafo
Errores comunes
- Marcar el vértice (asignar L[w]) solo cuando sale de la cola, y no cuando entra: el mismo vértice terminaría encolado varias veces.
- Olvidar la condición L[w] > L[v] al clasificar aristas de hermano y de primo: garantiza que cada arista se explore una sola vez.
- En un grafo ponderado, la búsqueda en anchura solo devuelve un camino de peso mínimo si todos los pesos son iguales; minimiza el número de aristas, no el peso.
Inicialización / Llamada inicialt ← 0; Cola ← ∅para todo vértice v ∈ V(G) hacerL[v] ← 0; nivel[v] ← 0; padre[v] ← nulomientras exista algún vértice v tal que L[v] = 0 hacert ← t + 1; L[v] ← t // v es la raíz de la búsquedaCola.Insertar(v)Ejecutar Búsqueda_Anchura()Búsqueda_Anchura()mientras not Cola.Vacía() hacerv ← Cola.Quitar()para todo vértice w ∈ Γ(v) hacersi L[w] = 0 entonces // arista de árbol (o padre)padre[w] ← v; nivel[w] ← nivel[v] + 1t ← t + 1; L[w] ← t; Cola.Insertar(w)si no, si nivel[w] = nivel[v] + 1 entoncesVisitar arista de tío {v, w}si no, si nivel[w] = nivel[v] y padre[v] = padre[w] y L[w] > L[v] entoncesVisitar arista de hermano {v, w}si no, si nivel[w] = nivel[v] y padre[v] ≠ padre[w] y L[w] > L[v] entoncesVisitar arista de primo {v, w}
Conectividad
Algoritmo de Kosaraju
Encuentra las componentes fuertemente conexas con dos búsquedas en profundidad: una en G y otra en el grafo inverso Gᴿ.
Idea central
Una primera búsqueda en profundidad en G registra los tiempos de finalización TF. La segunda búsqueda, hecha en el grafo inverso Gᴿ y tomando los vértices en orden decreciente de TF, produce un bosque en el que cada árbol es exactamente una componente fuertemente conexa.
Invariante
El orden decreciente de tiempo de finalización garantiza que la búsqueda en Gᴿ iniciada en un vértice nunca escapa de la componente fuertemente conexa a la que pertenece.
Requisitos del grafo
Errores comunes
- Olvidar construir el grafo inverso Gᴿ antes de la segunda búsqueda.
- Recorrer la segunda búsqueda en orden creciente de TF en lugar de decreciente.
- Confundir los tres niveles de conectividad de un grafo dirigido conexo: débilmente conexo (el grafo subyacente es conexo), unilateralmente conexo (para todo par, uno alcanza al otro) y fuertemente conexo (todos mutuamente alcanzables).
Algoritmo de Kosaraju1. Hacer una búsqueda en profundidad en G// guardar el tiempo de finalización TF de cada vértice2. Construir el grafo inverso (o traspuesto) Gᴿ// si (v, w) ∈ E(G) entonces (w, v) ∈ E(Gᴿ)3. Hacer una búsqueda en profundidad en Gᴿ tomando losvértices en orden decreciente de TFCada árbol del bosque de profundidad obtenido en el paso 3corresponde a una componente fuertemente conexa de G.
Grafos eulerianos
Algoritmo de Fleury
Construye un camino euleriano recorriendo el grafo y evitando cruzar un puente mientras haya otra arista disponible.
Idea central
Un grafo conexo es euleriano si y solo si todos sus vértices tienen grado par (teorema de Euler), y semieuleriano si existen exactamente dos vértices de grado impar. El algoritmo recorre el grafo eliminando las aristas recorridas y evita cruzar un puente mientras haya otra opción.
Invariante
El camino construido nunca repite aristas y, al evitar puentes, mantiene conexas las aristas restantes de G', lo que garantiza que el recorrido solo termine cuando todas hayan sido recorridas.
Requisitos del grafo
Errores comunes
- Cruzar un puente mientras existe otra arista disponible: las aristas del otro lado quedan inalcanzables y el camino termina antes de tiempo.
- Empezar por un vértice de grado par en un grafo semieuleriano: el camino debe partir de uno de los dos vértices de grado impar.
- Confundirlo con un grafo hamiltoniano: un camino euleriano pasa una vez por cada arista; uno hamiltoniano, una vez por cada vértice.
Algoritmo de Fleury1. si V(G) tiene 3 o más vértices de grado impar entonces PARAR2. Sea G' = (V', E') tal que V' ← V(G) y E' ← E(G)3. Seleccionar un vértice inicial v ∈ V'(elegir un v de grado impar, si lo hay)4. mientras E' ≠ ∅ hacera. si d(v) > 1 entoncesSeleccionar una arista {v, w} que no sea puente en G'si noSeleccionar la única arista {v, w} disponible en G'c. v ← w; E' ← E' − {v, w}// Caminar de v a w y eliminar la arista recorrida
Árbol de expansión mínima
Algoritmo de Prim
Incluye vértices uno a uno: en cada paso añade la arista de menor peso entre V(T) y los vértices aún no seleccionados.
Idea central
Construye el árbol de expansión mínima (AEM) de forma voraz, incluyendo los vértices uno a uno. Partiendo de una raíz r, en cada paso añade la arista de menor peso con un extremo en V(T) (ya seleccionados) y el otro fuera de V(T).
Invariante
En cada iteración, T = (V(T), E(T)) es un árbol y está contenido en algún árbol de expansión mínima de G.
Requisitos del grafo
Errores comunes
- Comparar el peso de la arista con la distancia acumulada desde la raíz en lugar del peso de la propia arista, lo que convertiría a Prim en Dijkstra.
- Aplicar Prim a un grafo dirigido: el problema correcto pasa a ser el de la arborescencia de peso mínimo.
- Un grafo no conexo no tiene árbol de expansión: un grafo G tiene árbol de expansión si y solo si G es conexo.
Algoritmo de Prim1. Elegir un vértice cualquiera r ∈ V(G) // raíz2. V(T) ← { r } // conj. de vértices seleccionados3. E(T) ← ∅ // conj. de aristas del AEM4. mientras V(T) ≠ V(G) hacera. Encontrar la arista {v, w} de menor peso tal quev ∈ V(T) y w ∉ V(T)b. Añadir w a V(T)c. Añadir {v, w} a E(T)Peso total: C(T) = Σ w , para e ∈ E(T)e
Árbol de expansión mínima
Algoritmo de Kruskal
Incluye aristas, no vértices: ordena las aristas por peso no decreciente y acepta cada una que no forme ciclo con las ya incluidas en E(T).
Idea central
Construye el AEM incluyendo aristas, y no vértices como en Prim. Ordena las aristas en orden no decreciente de peso y acepta, en cada iteración, la arista de menor peso que no forme ciclo con las ya incluidas en E(T).
Invariante
En cada iteración, T = (V(T), E(T)) es un bosque de expansión contenido en algún árbol de expansión mínima de G.
Requisitos del grafo
Errores comunes
- Suponer que bastan n − 1 iteraciones: se necesitan al menos n − 1, pero pueden ser más, ya que las aristas que forman ciclo deben descartarse.
- Aceptar una arista cuyos extremos ya están unidos por aristas de E(T): cerraría un ciclo.
- En un grafo no conexo el resultado es un bosque de expansión mínima, no un árbol de expansión.
Algoritmo de Kruskal1. Ordenar las aristas en orden no decreciente de peso:e₁, e₂, e₃, . . .2. V(T) ← V(G) // todos los vértices entran en el AEM3. E(T) ← { e₁ }4. j ← 2 // arista a analizar5. mientras | E(T) | < | V(T) | − 1 hacera. si la arista e no forma ciclo con las aristas de E(T)jentonces Añadir e a E(T)jb. j ← j + 1
Caminos mínimos
Algoritmo de Dijkstra
"Cierra" un vértice por iteración, siempre el de menor dist, y relaja las aristas tensas que salen de él.
Idea central
Resuelve el problema del camino mínimo desde una única raíz s. Se basa en el principio de relajación y "cierra" un vértice por iteración: elige el vértice aún no cerrado con el menor valor de dist y relaja las aristas tensas que salen de él.
Invariante
Para todo v ∈ S, dist[v] ya es el peso del camino mínimo desde la raíz hasta v. Al final, dist[ ] guarda los pesos de los caminos mínimos; los caminos en sí se recuperan con la lista de predecesores pred[ ].
Requisitos del grafo
Errores comunes
- Aplicar el algoritmo a un grafo con una arista de peso negativo: falla. Reponderar sumando una constante a todas las aristas también puede fallar.
- Reabrir un vértice que ya pertenece a S: una vez cerrado, su dist ya no cambia.
- Creer que dist[ ] devuelve los caminos: sin pred[ ] solo se obtienen los pesos.
Operación de relajaciónsi dist[v] + d < dist[w] entonces // ¿la arista (v, w) está tensa?vwdist[w] ← dist[v] + dvwpred[w] ← vAlgoritmo de Dijkstra1. para todo vértice v ∈ V(G) hacerdist[v] ← ∞; pred[v] ← nulo2. dist[s] ← 0 // s es la raíz de la búsqueda3. S ← ∅ // conjunto de vértices cerrados4. mientras S ≠ V(G) hacera. Elegir el vértice v ∉ S de menor dist[v]b. S ← S ∪ { v } // "cerrar" el vértice vc. para todo vértice w ∈ Γ⁺(v) hacersi dist[w] > dist[v] + d entonces // ¿arista tensa?vwdist[w] ← dist[v] + dvwpred[w] ← v
Caminos mínimos
Algoritmo de Bellman-Ford
Programación dinámica: examina todas las aristas en cada iteración, relajando las que estén tensas, durante |V(G)| − 1 iteraciones.
Idea central
Calcula caminos mínimos mediante programación dinámica. En lugar de "cerrar" un vértice por iteración, como Dijkstra, examina todas las aristas en cada iteración. Como cualquier camino en un grafo con n vértices tiene como máximo n − 1 aristas, bastan n − 1 iteraciones.
Invariante
Tras la i-ésima iteración, dist[w] es como máximo el peso del camino más corto de s a w que usa hasta i aristas.
Requisitos del grafo
Errores comunes
- Si en alguna iteración ninguna arista está tensa, el algoritmo puede terminar: las iteraciones siguientes no traerían actualizaciones.
- Si hay un ciclo de peso negativo entre s y t, no existe camino mínimo entre ellos; sin ese ciclo, el camino mínimo es simple (no repite vértices).
- Una arista no dirigida con peso negativo ya es, por sí sola, un ciclo de peso negativo.
Operación de relajaciónsi dist[v] + d < dist[w] entonces // ¿la arista (v, w) está tensa?vwdist[w] ← dist[v] + dvwpred[w] ← vAlgoritmo de Bellman-Ford1. para todo vértice v ∈ V(G) hacerdist[v] ← ∞; pred[v] ← nulo2. dist[s] ← 03. para i = 1, . . ., | V(G) | − 1 hacerpara cada (v, w) ∈ E(G) hacersi dist[w] > dist[v] + d entonces // ¿arista tensa?vwdist[w] ← dist[v] + dvwpred[w] ← vSi aún hay alguna arista tensa tras la última iteración,entonces el grafo tiene un ciclo de peso negativo.
Caminos mínimos
Algoritmo de Floyd-Warshall
Caminos mínimos entre todos los pares mediante programación dinámica: la ronda k habilita el vértice k como intermedio.
Idea central
Programación dinámica sobre el conjunto de vértices intermedios permitidos. Con los vértices numerados de 1 a n, distᵏ[i, j] es la distancia entre i y j usando como intermedios solo los vértices de { 1, 2, . . ., k }.
Invariante
Al final de la ronda k, dist[i, j] es el peso del camino más corto de i a j que usa solo { 1, . . ., k } como vértices intermedios; pred[i, j] guarda el penúltimo vértice de ese camino.
Requisitos del grafo
Errores comunes
- Cambiar el orden de los bucles: k debe ser el bucle más externo.
- Actualizar el predecesor con pred[i, k] en lugar de pred[k, j]: pred[i, j] es el penúltimo vértice del camino de i a j.
- Una entrada negativa en la diagonal, es decir, dist[i, i] < 0, indica un ciclo de peso negativo.
Relajación de la longitud de los caminosdistᵏ[i, j] = min( distᵏ⁻¹[i, j],distᵏ⁻¹[i, k] + distᵏ⁻¹[k, j] )con dist⁰[i, j] = d si (i, j) ∈ E(G); ∞ en otro caso;ijy dist⁰[i, i] = 0Algoritmo de Floyd-Warshall1. para i = 1, . . ., n hacerpara j = 1, . . ., n | j ≠ i hacerdist[i, j] ← ∞; pred[i, j] ← nulodist[i, i] ← 0; pred[i, i] ← i2. para toda arista (i, j) ∈ E(G) hacerdist[i, j] ← d ; pred[i, j] ← iij3. para k = 1, . . ., n hacer // cada posible intermediopara i = 1, . . ., n hacerpara j = 1, . . ., n hacersi dist[i, j] > dist[i, k] + dist[k, j] entoncesdist[i, j] ← dist[i, k] + dist[k, j]pred[i, j] ← pred[k, j]
Flujo máximo
Método de Ford-Fulkerson
Mientras exista algún camino aumentante en G'(f), envía por él el cuello de botella δ y actualiza la red residual.
Idea central
Mientras exista un camino aumentante de la fuente s al sumidero t en la red residual G′(f), se envía por él lo máximo posible, el cuello de botella δ, y se actualiza la red residual. Las aristas inversas permiten deshacer envíos anteriores.
Invariante
El flujo f respeta siempre la restricción de capacidad, 0 ≤ f(e) ≤ u(e), y la conservación del flujo en todo nodo interno. Por el teorema de flujo máximo y corte mínimo, al final el valor del flujo es igual a la capacidad del corte s-t mínimo.
Requisitos del grafo
Errores comunes
- Olvidar crear la arista inversa en la red residual, lo que impide deshacer envíos hechos en iteraciones anteriores.
- Elegir caminos aumentantes arbitrarios: con capacidades irracionales el método puede no terminar. Elegir siempre el camino aumentante con menos aristas (búsqueda en anchura) es el algoritmo de Edmonds-Karp.
- Suponer que el corte mínimo es cualquier corte: en la solución óptima, S es el conjunto de vértices alcanzables desde la fuente s en la red residual final.
Red residual G′(f): V(G′) = V(G) y, para e = (v, w) ∈ E:si f(e) < u(e): arista directa (v, w) con u (e) = u(e) − f(e)rsi f(e) > 0: arista inversa (w, v) con capacidad f(e)Método de Ford-Fulkerson1. para toda arista e ∈ E(G) hacer f(e) ← 02. Construir la red residual G′(f)3. mientras exista un camino aumentante P en G′(f) hacera. δ ← min { u (e) | e ∈ P } // "cuello de botella" de Prb. para cada arista (v, w) ∈ P haceri. si (v, w) es una arista directa entoncesf(v, w) ← f(v, w) + δ // aumentar el flujoii. si nof(w, v) ← f(w, v) − δ // reducir el flujoc. Actualizar la red residual G′(f)
Flujo máximo
Algoritmo de Edmonds-Karp
Implementación eficiente de Ford-Fulkerson: en cada iteración elige el camino aumentante más corto, obtenido mediante una búsqueda en anchura.
Idea central
Implementación eficiente del método de Ford-Fulkerson: en cada iteración selecciona el camino aumentante más corto de la red residual, es decir, el que usa el menor número de aristas. Ese camino se encuentra con una búsqueda en anchura.
Invariante
La longitud del camino aumentante elegido nunca disminuye de una iteración a la siguiente. Hay como máximo O(n·m) caminos aumentantes y cada uno se encuentra en O(m), de ahí O(n·m²).
Requisitos del grafo
Errores comunes
- Usar búsqueda en profundidad: se vuelve al método genérico de Ford-Fulkerson, que es solo pseudopolinomial, O(m·f), con f igual al valor del flujo máximo.
- En la red con dos aristas de capacidad 100 unidas por una de capacidad 1, la elección arbitraria puede requerir 200 iteraciones; la elección del camino más corto requiere 2.
- Olvidar que el algoritmo fue publicado de forma independiente por Dinitz (1970) y por Edmonds y Karp (1972).
Algoritmo de Edmonds-Karp1. para toda arista e ∈ E(G) hacer f(e) ← 02. Construir la red residual G′(f)3. mientras exista algún camino aumentante P en G′(f) hacera. Sea P el camino aumentante en G′(f) con menor númerode aristas // obtenido por búsqueda en anchurab. δ ← min { u (e) | e ∈ P }rc. para cada arista (v, w) ∈ P haceri. si (v, w) es una arista directa entoncesf(v, w) ← f(v, w) + δii. si nof(w, v) ← f(w, v) − δd. Actualizar la red residual G′(f)
Flujo máximo
Algoritmo de Dinic
En cada iteración construye la red de niveles GL a partir de G′(f) y determina en ella un flujo bloqueante.
Idea central
En lugar de aumentar un camino cada vez, construye la red de niveles GL a partir de G′(f) y determina en ella un flujo bloqueante completo. Como el número de niveles crece al menos en una unidad en cada iteración, hay como máximo n − 1 flujos bloqueantes.
Invariante
dist(t) crece estrictamente entre iteraciones, así que hay como máximo n − 1 flujos bloqueantes. Cada flujo bloqueante se obtiene en O(n·m), de ahí O(n²·m).
Requisitos del grafo
Errores comunes
- Buscar caminos fuera de GL: solo valen las aristas (v, w) con dist(w) = dist(v) + 1.
- Reconstruir la red de niveles tras cada camino en lugar de tras cada flujo bloqueante: lo que caracteriza una iteración es el flujo bloqueante completo.
- Detenerse cuando un camino se satura: el flujo bloqueante solo termina cuando ya no existe ningún camino de s a t en GL.
Red de niveles GL: V(GL) = V(G′) y, para (v, w) ∈ E(G′):(v, w) ∈ E(GL) con capacidad u (e) si dist(w) = dist(v) + 1,rdonde dist(v) es la menor distancia geodésica de s a vFlujo bloqueante fb: flujo en GL tal que, conservando solo lasaristas con capacidad mayor que fb, ya no exista ningúncamino aumentante en GLAlgoritmo de Dinic1. para toda arista e ∈ E(G) hacer f(e) ← 02. Construir la red residual G′(f)3. Construir la red de niveles GL a partir de G′(f)4. mientras dist(t) < ∞ hacera. Determinar un flujo bloqueante fb en GLb. Actualizar el flujo f usando fbc. Actualizar la red residual G′(f)d. Construir la red de niveles GL a partir de G′(f)
Ordenación topológica
Algoritmo de Kahn
En cada paso toma un vértice con grado de entrada cero, lo añade al final del resultado y reduce el grado de entrada de sus sucesores.
Idea central
En cada paso determina un vértice sin aristas de entrada, es decir, con d⁻(v) = 0, y lo inserta al final del resultado. En lugar de eliminar las aristas, mantiene y actualiza un mapa M con el grado de entrada de cada vértice.
Invariante
Un vértice solo entra en la cola cuando todos sus predecesores ya están en Orden_Top, así que ord(v) < ord(w) para toda arista (v, w) ∈ E(G).
Requisitos del grafo
Errores comunes
- Aplicarlo a un grafo no dirigido o con ciclos: no se puede establecer una relación de precedencia y el orden topológico no existe.
- Interpretar la cola vacía con vértices pendientes como un error: es exactamente así como el algoritmo detecta la existencia de un ciclo.
- Suponer que el orden es único: un grafo acíclico dirigido puede tener varios órdenes topológicos válidos.
Algoritmo de Kahn1. para todo vértice v hacer M[v] ← d⁻(v)2. Cola ← ∅; Orden_Top ← ∅3. para todo vértice v tal que d⁻(v) = 0 hacerCola.Insertar(v)4. mientras not Cola.Vacía() hacera. v ← Cola.Quitar()b. Orden_Top.InsertarAlFinal(v)c. para todo vértice w ∈ Γ⁺(v) haceri. M[w] ← M[w] − 1ii. si M[w] = 0 entonces Cola.Insertar(w)5. Si se procesaron todos los vértices, ÉXITO;en otro caso, existe un CICLO
Ordenación topológica
Ordenación topológica por búsqueda en profundidad
Descrito por Tarjan en 1976: inserta cada vértice al principio del resultado solo después de visitar todos los que dependen de él.
Idea central
Alternativa basada en la búsqueda en profundidad, descrita por Tarjan en 1976. Cada vértice se inserta en el resultado solo después de todos los que dependen de él, y la inserción se hace al principio de la lista, de ahí el orden inverso.
Invariante
Cuando v recibe la marca permanente, todos los vértices alcanzables desde v ya están en Orden_Top. Como v se inserta al principio, los precede a todos en el orden.
Requisitos del grafo
Errores comunes
- Insertar al final en lugar de al principio: el orden sale invertido. El orden correcto es el inverso del orden de inserción, equivalente al orden decreciente de tiempo de finalización.
- No distinguir la marca temporal de la permanente: solo volver a encontrar una marca temporal revela un ciclo; la permanente indica un vértice ya resuelto.
- Confundirlo con el bosque de profundidad común: aquí lo que importa es el orden de finalización, no el árbol.
Método por búsqueda en profundidad1. para todo vértice v hacer Marca[v] ← 02. Orden_Top ← ∅3. mientras exista algún vértice v tal que Marca[v] = 0hacer Visita(v)Visita(v)1. si Marca[v] ≠ 2 entonces // si v no es permanentea. si Marca[v] = 1 entonces CICLO // marca temporalb. Marca[v] ← 1 // marca temporalc. para todo vértice w ∈ Γ⁺(v) hacer Visita(w)d. Marca[v] ← 2 // marca permanentee. Orden_Top.InsertarAlPrincipio(v)
Emparejamiento
Algoritmo de Edmonds
Busca caminos M-aumentantes entre vértices expuestos, contrayendo las flores (blossoms) que aparecen, hasta que no quede ninguno.
Idea central
Por el teorema de Berge, M tiene cardinalidad máxima si y solo si no existe ningún camino M-aumentante. El algoritmo busca esos caminos en un bosque M-alternante; cuando una arista une dos vértices a distancia par del mismo árbol, aparece un ciclo impar, la flor (blossom), que se contrae en un pseudovértice.
Invariante
M ⊕ EP es siempre un emparejamiento con una arista más que M. Por el teorema de Edmonds, M es máximo en G si y solo si M/B es máximo en G/B, lo que justifica la contracción de las flores.
Requisitos del grafo
Errores comunes
- Usar solo búsqueda en anchura o en profundidad en un grafo general: sin tratar las flores, caminos M-aumentantes existentes dejan de encontrarse.
- Ignorar la arista {v, w} cuando dist(w, F.raíz[w]) es impar: no genera un camino aumentante.
- Confundir emparejamiento maximal con máximo: maximal solo significa que no admite añadir más aristas; máximo es el de mayor cardinalidad. Y un emparejamiento máximo no implica un emparejamiento perfecto.
Emparejamiento_Máximo(G)1. M ← ∅2. P ← Buscar_Camino_Aumentante(G, M)3. mientras (P ≠ ∅) hacera. M ← M ⊕ EPb. P ← Buscar_Camino_Aumentante(G, M)Buscar_Camino_Aumentante(G, M)1. F ← Inicializar_Bosque_Alternante(G, M)2. para todo vértice sin marcar v ∈ F tal quedist(v, F.raíz[v]) sea par hacera. mientras ∃ arista e = {v, w} sin marcar haceri. si w ∉ F entonces Añadir_al_Bosque(M, F, v, w)ii. si no, si dist(w, F.raíz[w]) es par entoncesdevolver Obtener_Nuevo_Camino(G, M, F, v, w)iii. Marcar la arista eb. Marcar el vértice v3. devolver ∅Obtener_Nuevo_Camino(G, M, F, v, w)1. si F.raíz[v] ≠ F.raíz[w] entoncesP ← ObtenerCamino(F, F.raíz[v], v)+ ObtenerCamino(F, w, F.raíz[w])2. si no // flor (blossom)a. B ← ObtenerCamino(F, v, w) + vb. G′ ← Contraer_Flor_Grafo(G, B, z)c. M′ ← Contraer_Flor_Emparejamiento(M, B, z)d. P ← Buscar_Camino_Aumentante(G′, M′)e. si z ∈ P entonces P ← Expandir_Flor(P, G, B, z)3. devolver P
Coloración
Coloración voraz
Recorre los vértices en cualquier orden y asigna a cada uno el color de menor índice que no use ninguno de sus vecinos.
Idea central
No existe un método eficiente para obtener la coloración mínima de un grafo, pero sí se puede obtener rápidamente una coloración aproximada: se recorren los vértices en cualquier orden y se asigna a cada uno el color de menor índice que no usen sus vecinos.
Invariante
En cada paso la coloración parcial es válida: color(v) ≠ color(w) para todo par de vértices adyacentes ya coloreados. Como un vértice tiene como máximo Δ(G) vecinos, el método nunca usa más de Δ(G) + 1 colores.
Requisitos del grafo
Errores comunes
- Tomar el número de colores obtenido como el número cromático: el resultado depende del orden de los vértices y en general χ(G) es menor.
- Olvidar las cotas conocidas: ω(G) ≤ χ(G) ≤ Δ(G) + 1 y, por el teorema de Brooks, χ(G) ≤ Δ(G) si G es simple, no completo y no es un ciclo impar.
- Aplicarlo a un grafo dirigido: la coloración de vértices está definida para grafos no dirigidos.
Método voraz1. Considerar los vértices del grafo en cualquier ordenv₁, v₂, . . ., vₙ2. Identificar los colores con índices, añadiendo máscolores cuando sea necesario3. Colorear v₁ con el primer color4. En cada iteración, asignar al vértice actual el colorde menor índice que no use ninguno de sus vecinos
Coloración
Algoritmo de Welsh-Powell
Ordena los vértices por grado no creciente y colorea con un mismo color todos los que no estén conectados a un vértice ya coloreado con él.
Idea central
Refinamiento del método voraz: los vértices se ordenan por grado no creciente y cada color se reparte en una pasada completa por la lista, coloreando todos los vértices que no estén conectados a uno ya coloreado con ese color.
Invariante
Cada color forma un conjunto independiente: ningún par de vértices con el mismo color es adyacente. El método termina porque cada pasada colorea al menos un vértice.
Requisitos del grafo
Errores comunes
- Tomar el resultado como óptimo: existe un contraejemplo en el que Welsh-Powell usa 3 colores en un grafo bipartito, para el cual χ(G) = 2.
- Abandonar el orden por grado al empezar un nuevo color: la lista ordenada se recorre desde el principio en cada pasada.
- Colorear un vértice adyacente a otro ya coloreado con el color de la pasada actual: la comprobación se hace contra los vértices ya coloreados con ese color.
Algoritmo de Welsh-Powell1. Ordenar los vértices por grado no crecientev₁, v₂, . . ., vₙ2. Identificar los colores con índices, añadiendo máscolores cuando sea necesario3. Colorear v₁ con el primer color4. Recorrer la lista de vértices coloreando todos losvértices no conectados a un vértice ya coloreado,usando siempre el mismo color5. Repetir el paso 4 para todos los vértices sin colorearusando un nuevo color, respetando siempre el orden degrado no creciente, hasta que todos estén coloreados