∫Atlas Matemáticas Aplicadas

Inicio › Temas › Optimización

🎯 Optimización nivel avanzado

Programación entera

Cuando las variables deben ser números enteros, redondear no basta: hay que ramificar y acotar.

🕹️ Ábrelo en el curso interactivo (simulador y código ejecutable)

La idea

Muchas decisiones no admiten fracciones: no se compran 2,4 camiones ni se abren 1,7 fábricas, y una variable binaria que decide «sí o no» solo puede valer 0 o 1. Añadir la condición x ∈ ℤ a un problema lineal produce un problema de programación entera, que ya no es convexo: la región factible pasa de ser un poliedro continuo a una nube de puntos aislados dentro de él.

La tentación es resolver la relajación lineal (ignorando la integralidad) y redondear. Es un error: el punto redondeado puede ser infactible (si el óptimo continuo está sobre una restricción, subir una coordenada la viola) y, aunque sea factible, puede estar muy lejos del óptimo entero, que a veces se encuentra en un vértice completamente distinto de la región. La diferencia entre el valor de la relajación y el del óptimo entero se llama brecha de integralidad, y la relajación siempre proporciona una cota: en un problema de maximización, z_LP ≥ z_ENT.

El algoritmo estándar es ramificación y acotación (branch and bound). Se resuelve la relajación; si la solución ya es entera, hemos terminado. Si alguna variable sale fraccionaria, digamos x = 3,4, se ramifica creando dos subproblemas con x ≤ 3 y con x ≥ 4, que juntos contienen todos los puntos enteros y excluyen el fraccionario. Cada rama se resuelve y se poda cuando su cota es peor que la mejor solución entera conocida, cuando es infactible o cuando ya da una solución entera. El árbol puede crecer exponencialmente —estos problemas son NP-difíciles—, pero las buenas cotas y los planos de corte permiten resolver en la práctica modelos con millones de variables binarias.

Fórmulas clave

  • Problema enteromax cᵀx s.a. A x ≤ b, x ≥ 0, x ∈ ℤⁿ
  • Relajación lineal (cota)z_LP ≥ z_ENT (en maximización)
  • Brecha de integralidadbrecha = z_LP − z_ENT ≥ 0
  • Ramificación sobre xⱼ = vrama A: xⱼ ≤ ⌊v⌋ rama B: xⱼ ≥ ⌈v⌉
  • Poda por cotasi z_LP(nodo) ≤ z_mejor → se descarta el nodo
  • Variable binariax ∈ {0, 1} ⇔ 0 ≤ x ≤ 1, x ∈ ℤ

Dónde se aplica

La planificación de turnos de hospitales y aerolíneas se formula con variables binarias «este empleado cubre este turno», y la localización de instalaciones decide con binarias qué almacenes abrir. En telecomunicaciones, asignar frecuencias a antenas sin interferencias es un problema entero equivalente a colorear un grafo. En finanzas, seleccionar una cartera con un número máximo de activos distintos exige binarias de «entra o no entra». Y los compiladores asignan registros a variables resolviendo, otra vez, un problema entero disfrazado de coloreado.

Con programación (Python)

# max z = 5x + 4y  s.a.  6x + 4y <= 24,  x + 2y <= 6,  x, y >= 0 enteros
def z(x, y):
    return 5 * x + 4 * y

def factible(x, y):
    return 6 * x + 4 * y <= 24 + 1e-9 and x + 2 * y <= 6 + 1e-9 and x >= 0 and y >= 0

# Optimo continuo: interseccion de las dos restricciones activas
xc, yc = 3.0, 1.5
print("Relajacion lineal: (%.2f, %.2f)  z = %.2f" % (xc, yc, z(xc, yc)))
print("Redondeo abajo (3, 1): factible =", factible(3, 1), " z =", z(3, 1))
print("Redondeo cercano (3, 2): factible =", factible(3, 2))

mejor = None
for x in range(0, 5):
    for y in range(0, 4):
        if factible(x, y) and (mejor is None or z(x, y) > z(mejor[0], mejor[1])):
            mejor = (x, y)
print("Optimo entero:", mejor, " z =", z(mejor[0], mejor[1]))
print("Brecha de integralidad:", z(xc, yc) - z(mejor[0], mejor[1]))
print("El optimo entero NO es el redondeo del continuo")

La versión en JavaScript, editable y ejecutable en el navegador, está en la página interactiva del tema.

Temas relacionados

Programación lineal · El problema de la mochila · Combinatoria y triángulo de Pascal

← Todos los temas