Se parte de una solución óptima cualquiera.
Algoritmos Voraces
Definición, componentes, modelado, demostración, ejemplos clásicos y comparación con Programación Dinámica.
Algoritmos Voraces: idea central
Un algoritmo voraz construye una solución paso a paso. En cada etapa mira los candidatos disponibles, escoge el que parece mejor según un criterio local y, si es factible, lo agrega al conjunto solución.
La característica peligrosa del voraz es que no reconsidera. Una vez acepta un candidato, ese candidato permanece en la solución. Si la elección local fue mala para el óptimo global, el algoritmo no se corrige solo.
Por eso los voraces son rápidos y simples, pero matemáticamente delicados. No basta con que la estrategia parezca razonable: hay que demostrar que esa regla local siempre conduce a una solución óptima, o aceptar que es solo una heurística.
La tensión central de los voraces
| Ventaja | Riesgo | Exigencia |
|---|---|---|
| Suelen ser rápidos y fáciles de implementar. | Pueden quedarse con una solución mala por una elección temprana. | Demostrar propiedad voraz o mostrar contraejemplo. |
Componentes de un algoritmo voraz
Un algoritmo voraz no se describe correctamente diciendo “escojo lo mejor”. Hay que especificar qué se escoge, con qué criterio, bajo qué restricciones y cuándo se considera terminada la solución.
Componentes formales de un algoritmo voraz
| Componente | Pregunta que responde | Ejemplo en cambio de monedas |
|---|---|---|
| Conjunto de candidatos | ¿Qué elementos puedo escoger? | Denominaciones disponibles. |
| Función de selección | ¿Cuál candidato parece mejor ahora? | La moneda más grande disponible. |
| Función de factibilidad | ¿Puedo agregar este candidato sin violar restricciones? | La moneda debe ser menor o igual al restante. |
| Conjunto solución | ¿Qué candidatos ya acepté? | Monedas acumuladas. |
| Función objetivo | ¿Qué quiero optimizar? | Minimizar el número de monedas. |
| Función comprobante | ¿La solución ya está completa? | El restante llegó a cero. |
La función de selección dice cuál candidato parece mejor. La función de factibilidad dice si ese candidato se puede aceptar. Un candidato puede ser el más atractivo y aun así ser inválido.
Modelo general de un algoritmo voraz
El modelo voraz tiene tres movimientos repetidos: seleccionar un candidato, verificar si es prometedor y actualizar la solución parcial. La forma exacta cambia por problema, pero el esqueleto es el mismo.
Modelo de selección voraz
En esta expresión, xt representa el candidato elegido en el paso t. El símbolo 'arg opt' indica que buscamos el elemento x, dentro del conjunto de candidatos Ct, que maximice o minimice el criterio local definido por el problema.
Modelo de actualización del conjunto solución
CSt es el conjunto solución acumulado. Si el candidato xt es factible (no rompe las reglas), se une al conjunto anterior usando el símbolo de unión (U). De lo contrario, la solución se mantiene igual.
Modelo de actualización de candidatos
Ct+1 define el nuevo conjunto de candidatos para la siguiente etapa. Dependiendo del problema, el candidato xt se descarta (resta de conjuntos) o permanece disponible para ser reutilizado.
algoritmoVoraz(Candidatos) BEGIN
CS <- {};
encontrado <- F;
WHILE (NOT vacio(Candidatos) AND NOT encontrado) DO BEGIN
x <- seleccionar(Candidatos);
IF (factible(x, CS)) THEN BEGIN
CS <- incluir(x, CS);
END
Candidatos <- remover(x, Candidatos);
IF (esSolucion(CS)) THEN BEGIN
encontrado <- T;
END
END
RETURN CS;
ENDEste esquema solo describe cómo se construye la solución. No demuestra que sea óptima. La correctitud depende de probar que la función de selección es válida para el problema específico.
Correctitud: propiedad voraz y subestructura óptima
El punto débil de los voraces es la correctitud. Implementar la selección local suele ser fácil; demostrar que esa selección local siempre lleva al óptimo global es lo difícil.
Condiciones para confiar en un voraz
| Condición | Significado | Pregunta de control |
|---|---|---|
| Propiedad voraz | Existe una solución óptima que contiene la elección local tomada por el algoritmo. | ¿Puedo demostrar que escoger este candidato ahora no destruye el óptimo? |
| Subestructura óptima | Después de tomar la decisión voraz, lo que queda sigue siendo un subproblema del mismo tipo. | ¿El problema restante se resuelve con la misma lógica? |
| Factibilidad acumulada | Cada decisión mantiene una solución parcial prometedora. | ¿Agregar el candidato conserva las restricciones? |
Plantilla de demostración voraz
El candidato es la elección local del algoritmo.
Se intenta reemplazar algún elemento de la solución óptima por la elección voraz sin empeorar la solución.
Según sea minimización o maximización, se prueba que el intercambio conserva optimalidad.
Después de fijar la elección voraz, el problema restante debe tener la misma estructura.
Si encuentras una sola entrada donde la regla voraz produce una solución peor que otra posible, la estrategia no es correcta en general. Puede seguir siendo una heurística, pero no un algoritmo exacto.
Ejemplo 1 — Cambio de monedas
El problema pide dar cambio exacto para una cantidad objetivo usando el menor número posible de monedas. La regla voraz natural es tomar en cada paso la moneda más grande que no exceda el restante.
Componentes del voraz para cambio de monedas
| Componente | Definición en el problema |
|---|---|
| Candidatos | Denominaciones disponibles. |
| Función de selección | Escoger la denominación más grande. |
| Factibilidad | La moneda debe ser menor o igual al restante. |
| Función objetivo | Minimizar el número total de monedas. |
| Comprobación | El restante debe llegar a cero. |
Modelo de selección
dt es el valor de la moneda elegida. Buscamos el valor máximo (max) en el conjunto de denominaciones D que no supere el dinero restante rt.
Modelo de actualización
rt+1 es la nueva cantidad de dinero que falta por entregar. Se calcula restando el valor de la moneda entregada dt al monto previo.
Modelo del conjunto solución
El conjunto solución se actualiza añadiendo la moneda dt si esta cumple la condición de ser menor o igual al restante.
cambioVoraz(D[n], objetivo) BEGIN
restante <- objetivo;
CS <- {};
WHILE (restante > 0) DO BEGIN
moneda <- seleccionarMayorFactible(D, restante);
IF (moneda = -1) THEN BEGIN
RETURN -1;
END
CS <- incluir(moneda, CS);
restante <- restante - moneda;
END
RETURN CS;
ENDEjecución para objetivo 17 y denominaciones {10, 4, 2, 1}
| Etapa | Candidato elegido | ¿Factible? | Restante | CS acumulado |
|---|---|---|---|---|
| 1 | 10 | Sí, 10 ≤ 17 | 17 - 10 = 7 | {10} |
| 2 | 4 | Sí, 4 ≤ 7 | 7 - 4 = 3 | {10, 4} |
| 3 | 2 | Sí, 2 ≤ 3 | 3 - 2 = 1 | {10, 4, 2} |
| 4 | 1 | Sí, 1 ≤ 1 | 1 - 1 = 0 | {10, 4, 2, 1} |
El algoritmo devuelve 4 monedas: {10, 4, 2, 1}. La suma es 17.
Con denominaciones {11, 5, 3, 2} y objetivo 15, el voraz toma 11, queda restante 4 y luego toma 3 y 1 si existiera, o falla si no hay moneda de valor 1. Pero la solución óptima es {5, 5, 5}, con solo 3 monedas.
El cambio de monedas solo es exacto con voraz para ciertos sistemas monetarios. Si el sistema de denominaciones no tiene la propiedad adecuada, el algoritmo puede ser rápido y aun así incorrecto.
Ejemplo 2 — Caballo en el ajedrez: regla de Warnsdorff
El problema consiste en recorrer un tablero de ajedrez con un caballo pasando una sola vez por cada casilla. En cada etapa, los candidatos son las casillas alcanzables por el movimiento del caballo.
Componentes voraces en Warnsdorff
| Componente | Definición |
|---|---|
| Candidatos | Casillas a las que el caballo puede moverse desde la posición actual. |
| Factibilidad | La casilla no debe haber sido visitada. |
| Función de selección | Escoger la casilla con menor número de movimientos futuros disponibles. |
| Conjunto solución | Secuencia de casillas visitadas por el caballo. |
| Comprobación | Todas las casillas fueron visitadas exactamente una vez. |
Modelo de selección de Warnsdorff
La función siguiente(v) elige la próxima casilla u que minimiza el 'grado disponible', es decir, la que tiene menos opciones de salida hacia casillas no visitadas.
Modelo de actualización
La ruta del caballo se extiende con la casilla elegida solo si existe al menos un movimiento factible desde la posición actual.
Decisión voraz en Warnsdorff
warnsdorff(tablero[n][n], inicio) BEGIN
actual <- inicio;
ruta <- {actual};
marcarVisitada(actual);
WHILE (longitud(ruta) < n * n) DO BEGIN
candidatos <- movimientosFactibles(actual, tablero);
IF (vacio(candidatos)) THEN BEGIN
RETURN -1;
END
siguiente <- candidatoMenorGrado(candidatos, tablero);
ruta <- incluir(siguiente, ruta);
marcarVisitada(siguiente);
actual <- siguiente;
END
RETURN ruta;
ENDLa regla de Warnsdorff es voraz porque escoge la casilla localmente más restrictiva. Puede funcionar muy bien, pero no debe venderse como demostración automática de solución óptima para cualquier variante del problema. Si no hay prueba, es heurística.
Ejemplo 3 — Selección de actividades
Dado un conjunto de actividades con hora de inicio y fin, se busca seleccionar el máximo número de actividades compatibles, es decir, actividades que no se solapen.
Componentes voraces en selección de actividades
| Componente | Definición |
|---|---|
| Candidatos | Actividades disponibles. |
| Función de selección | Elegir la actividad que termina más temprano. |
| Factibilidad | La actividad debe iniciar después o justo cuando termina la última actividad seleccionada. |
| Función objetivo | Maximizar el número de actividades seleccionadas. |
Modelo de selección
at representa la actividad elegida. Se busca aquella que tenga el tiempo de finalización (fin(a)) más temprano entre todas las que inician después de que termine la última actividad ya aceptada.
Modelo de actualización
El conjunto de actividades seleccionadas CS crece solo si la nueva actividad at es compatible con el horario de la última actividad del conjunto.
Ejemplo de selección de actividades
| Actividad | Inicio | Fin |
|---|---|---|
| A1 | 1 | 4 |
| A2 | 3 | 5 |
| A3 | 0 | 6 |
| A4 | 5 | 7 |
| A5 | 8 | 9 |
| A6 | 5 | 9 |
Ejecución voraz
La regla voraz trabaja con la actividad que termina más temprano.
Es la primera actividad que termina.
Ambas se solapan con A1.
A4 es compatible y termina antes que las demás compatibles.
A5 es compatible con la última seleccionada.
Se seleccionan tres actividades compatibles.
seleccionarActividades(inicio[n], fin[n]) BEGIN
ordenarPorFin(inicio, fin);
CS <- {};
ultimoFin <- 0;
FOR i <- 1 TO n DO BEGIN
IF (inicio[i] >= ultimoFin) THEN BEGIN
CS <- incluir(i, CS);
ultimoFin <- fin[i];
END
END
RETURN CS;
ENDElegir la actividad que termina más temprano deja el mayor espacio posible para las actividades restantes. Mediante argumento de intercambio, si una solución óptima empieza con otra actividad compatible que termina después, se puede reemplazar por la que termina antes sin reducir el número total de actividades.
Cuándo usar Voraces vs Programación Dinámica
Voraz y Programación Dinámica pueden aparecer en problemas de optimización, pero no razonan igual. El voraz se compromete con una decisión local. PD evalúa alternativas y guarda subproblemas.
Algoritmo Voraz vs Programación Dinámica
| Criterio | Algoritmo Voraz | Programación Dinámica |
|---|---|---|
| Garantía de óptimo | Solo si se demuestra la propiedad voraz. | Sí, si el modelo cumple principio de optimalidad y se evalúan los estados necesarios. |
| Reconsideración | No reconsidera decisiones aceptadas. | Evalúa alternativas y conserva mejores valores. |
| Velocidad | Generalmente más rápido. | Puede ser más lento porque llena tablas o memoria. |
| Memoria | a | o más, según la tabla. |
| Aplicabilidad | Problemas con propiedad voraz demostrable. | Problemas con subproblemas solapados y decisiones entre alternativas. |
Decisión entre Voraz y Programación Dinámica
Si no puedes demostrar que la elección local es segura, no tienes un algoritmo voraz correcto. Tienes una conjetura. Para clase, eso no alcanza.
Errores típicos en algoritmos voraces
Errores frecuentes en algoritmos voraces
| Error | Por qué está mal | Corrección |
|---|---|---|
| Confundir óptimo local con óptimo global | Una decisión buena ahora puede bloquear una solución mejor después. | Demostrar propiedad voraz o buscar contraejemplo. |
| No definir función de factibilidad | El algoritmo puede agregar candidatos que violan restricciones. | Separar selección de factibilidad. |
| Decir que es correcto porque parece intuitivo | La intuición no prueba optimalidad. | Usar intercambio, corte o inducción según el problema. |
| Ignorar contraejemplos pequeños | Un solo contraejemplo invalida la estrategia general. | Probar con entradas adversas antes de afirmar correctitud. |
| Llamar voraz a cualquier algoritmo rápido | La velocidad no define la técnica. | Debe existir selección local irrevocable por etapas. |
| Usar voraz donde se requiere reconsiderar | Si el problema exige comparar combinaciones completas, PD o búsqueda pueden ser necesarias. | Comparar contra Programación Dinámica, Backtracking o Branch and Bound. |
Resumen operativo
- Define el conjunto de candidatos.
- Define la función objetivo: qué quieres maximizar o minimizar.
- Define la función de selección local.
- Define la función de factibilidad.
- Define cómo se actualiza el conjunto solución.
- Define cuándo termina el algoritmo.
- Demuestra la propiedad voraz o encuentra un contraejemplo.
- Analiza complejidad temporal y espacial.
Fórmulas y modelos clave
La elección depende solo de la etapa actual.
Solo se agregan candidatos que conservan las restricciones.
Muchos voraces ordenan candidatos y luego hacen un recorrido lineal. Por eso aparecen costos típicos como .
Sin estas propiedades, la estrategia puede ser solo heurística.