Kruskal y Prim
Dos algoritmos golosos para conectar todo al menor costo posible. Uno ordena las aristas y evita ciclos; el otro hace crecer un árbol desde un vértice. Los dos son correctos por la misma propiedad.
Para este tema conviene tener claro:Conjuntos disjuntos (union-find)
Conectar un conjunto de puntos —ciudades, nodos de una red, componentes de un circuito— gastando lo menos posible en enlaces. La respuesta es un árbol generador mínimo, y hay dos formas clásicas de construirlo, las dos golosas y las dos correctas por la misma razón de fondo.
Conectar todo con el menor peso total
Dado un grafo no dirigido, conexo y con pesos, se busca el subconjunto de aristas que conecte todos los vértices con peso total mínimo. Ese subconjunto no puede tener ciclos: sacar una arista de un ciclo mantiene la conexión y baja el costo.
Un árbol sobre vértices tiene exactamente aristas. El problema es elegir cuáles, y hacerlo bien entre una cantidad astronómica de árboles posibles.
Antes de seguir, predecí
La propiedad del corte, que justifica a los dos
Lo que justifica a los dos algoritmos es la propiedad del corte. Si se parte el conjunto de vértices en dos, la arista más liviana que cruza esa división pertenece a algún árbol generador mínimo.
La demostración es un intercambio: si un árbol óptimo no la incluye, agregarla forma un ciclo que necesariamente cruza la división por otra arista más pesada; cambiarla por la liviana da un árbol igual de válido y no más caro. Kruskal y Prim son dos maneras de elegir el corte.
Cinco vértices y seis aristas con sus pesos. Buscamos las cuatro que conecten todo con el menor peso total.
Kruskal: ordenar aristas y evitar ciclos
Kruskal ordena todas las aristas por peso creciente y las va tomando, salteando las que conectarían dos vértices del mismo grupo —que formarían ciclo—. Termina con aristas.
La pregunta “¿ya están conectados?” es exactamente lo que responde union-find. Ordenar domina el costo: , y las consultas de conjuntos disjuntos son prácticamente constantes. Durante la ejecución hay varios fragmentos sueltos que recién al final se unen en un árbol.
Prim: hacer crecer un solo árbol
Prim arranca de un vértice cualquiera y hace crecer un único árbol: en cada paso agrega la arista más liviana que conecta el árbol con un vértice de afuera.
La estructura que hace falta es una cola de prioridad con los vértices pendientes, ordenados por el costo de engancharlos. El costo es , y el parecido con Dijkstra es más que superficial: la única diferencia es qué se guarda en la cola —el peso de la arista de conexión, no la distancia acumulada desde el origen—.
Cuál conviene según la densidad
En grafos ralos suele convenir Kruskal, sobre todo si las aristas ya vienen ordenadas o se pueden ordenar barato: ahí el algoritmo es casi lineal. En grafos densos conviene Prim, que no necesita mirar todas las aristas de entrada y con una implementación matricial da .
Hay un detalle sobre la unicidad: si todos los pesos son distintos, el árbol generador mínimo es único y los dos algoritmos devuelven el mismo. Con pesos repetidos pueden dar árboles distintos, ambos óptimos.
Dónde aparece, además del tendido de redes
Más allá del tendido de redes, el árbol generador mínimo aparece en clustering: sacarle las aristas más pesadas parte los datos en grupos separados, que es el clustering de enlace simple.
También sirve como cota inferior en branch and bound para el viajante de comercio. Y una advertencia importante: conectar todo al mínimo costo no es lo mismo que minimizar la distancia entre dos puntos. El camino entre dos vértices dentro del árbol puede ser mucho peor que el camino mínimo del grafo.
Cuál de los dos, y para qué sirve un árbol generador
| Kruskal | Prim | |
|---|---|---|
| Cómo elige | la arista más liviana que no cierre ciclo | la más liviana que salga del árbol actual |
| Estructura que necesita | union-find, y ordenar las aristas | cola de prioridad |
| Costo | O(E log E) | O(E log V) con heap |
| Conviene cuando | el grafo es ralo | el grafo es denso |
| Si el grafo no es conexo | da un bosque: sirve igual | sólo cubre la componente del origen |
| Se puede parar a la mitad | no: las aristas están sueltas | sí: siempre hay un árbol válido |
Más a fondo · formalUnicidad, y qué pasa con pesos repetidos
Si todos los pesos son distintos, el árbol generador mínimo es único. La demostración es por contradicción: si hubiera dos, la arista de menor peso que está en uno y no en el otro produce, al agregarla al segundo, un ciclo con alguna arista más pesada, y el intercambio daría un árbol más liviano que el supuesto óptimo.
Con pesos repetidos puede haber varios óptimos, todos del mismo peso total, y ahí aparece un detalle que muerde en producción: dos corridas del mismo algoritmo sobre los mismos datos pueden devolver árboles distintos si el criterio de desempate depende del orden de iteración, que en algunos lenguajes no está garantizado. Si el resultado se compara entre corridas —en un test, en un despliegue— conviene fijar el desempate explícitamente.
Cierre
Kruskal ordena aristas y evita ciclos con union-find; Prim hace crecer un árbol con una cola de prioridad. Los dos son golosos y correctos por la propiedad del corte: la arista más liviana que cruza una división siempre entra en algún óptimo.
Autoevaluación
¿Lo entendiste?
Práctica