WhatsApp

  

Algoritmo del Problema de la Mochila 0-1: Conceptos, Implementación en Python y Mejores Prácticas

Guía completa sobre el problema de la mochila 0-1, su formulación matemática, solución con programación dinámica en Python y técnicas avanzadas de optimización y depuración.

Problema de la Mochila 0-1 (0‑1 Knapsack)

1. ¿Qué es la mochila 0-1?

El problema de la mochila 0-1 es un clásico de la optimización combinatoria. Dado un conjunto de n ítems, cada uno con un peso w_i y un valor v_i, y una capacidad máxima W de la mochila, debemos seleccionar un subconjunto de ítems de forma que:

  • La suma de los pesos no supere W.
  • El valor total sea máximo.

La restricción "0‑1" indica que cada ítem puede estar una sola vez (0 = no tomado, 1 = tomado). No se permiten fracciones.

2. Formulación matemática

max  Σ v_i·x_i
s.t. Σ w_i·x_i ≤ W
     x_i ∈ {0,1}   ∀ i = 1…n

Donde x_i es la variable de decisión que indica si el ítem i se incluye.

3. Solución con Programación Dinámica (DP)

La DP construye una tabla dp[i][c] que representa el valor máximo alcanzable usando los primeros i ítems con capacidad c. La recurrencia es:

dp[i][c] = dp[i-1][c]                              // no tomar el ítem i
if w_i ≤ c:
    dp[i][c] = max(dp[i][c], dp[i-1][c-w_i] + v_i)   // tomar el ítem i

La complejidad temporal es O(n·W) y la espacial O(n·W). Con una optimización de espacio podemos reducirla a O(W) usando una sola fila y recorriendo la capacidad en sentido descendente.

4. Implementación en Python (versión clásica)

def knapsack_01(weights, values, capacity):
    n = len(weights)
    # tabla DP de (n+1) x (capacity+1)
    dp = [[0] * (capacity + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        w = weights[i-1]
        v = values[i-1]
        for c in range(capacity + 1):
            dp[i][c] = dp[i-1][c]                 # no tomar
            if w <= c:
                dp[i][c] = max(dp[i][c], dp[i-1][c-w] + v)  # tomar
    return dp[n][capacity]
# Ejemplo de uso
weights = [2, 3, 4, 5]
values  = [3, 4, 5, 6]
capacity = 5
print(knapsack_01(weights, values, capacity))  # → 7 (ítems 1 y 2)

Salida esperada: 7 (seleccionamos los ítems con peso 2 y 3).

5. Optimización de espacio (O(W) memoria)

def knapsack_01_optimized(weights, values, capacity):
    n = len(weights)
    dp = [0] * (capacity + 1)
    for i in range(n):
        w, v = weights[i], values[i]
        # recorrer de mayor a menor para evitar reutilizar el ítem en la misma iteración
        for c in range(capacity, w-1, -1):
            dp[c] = max(dp[c], dp[c-w] + v)
    return dp[capacity]
print(knapsack_01_optimized(weights, values, capacity))  # → 7

Esta versión es ideal cuando W es grande y la tabla completa no cabe en memoria.

6. Recuperar los ítems seleccionados

def knapsack_items(weights, values, capacity):
    n = len(weights)
    dp = [[0] * (capacity + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        w, v = weights[i-1], values[i-1]
        for c in range(capacity + 1):
            dp[i][c] = dp[i-1][c]
            if w <= c:
                dp[i][c] = max(dp[i][c], dp[i-1][c-w] + v)
    # backtrack para obtener los ítems
    res, c = [], capacity
    for i in range(n, 0, -1):
        if dp[i][c] != dp[i-1][c]:
            res.append(i-1)          # índice del ítem
            c -= weights[i-1]
    res.reverse()
    return dp[n][capacity], res
valor, items = knapsack_items(weights, values, capacity)
print('Valor máximo:', valor)
print('Ítems elegidos:', items)   # → [0, 1]

7. Comparativa con otras variantes

0‑1 Knapsack vs. Fraccionario
  • Tipo de decisión: Binaria vs. continua.
  • Complejidad: O(n·W) (NP‑completo) vs. O(n log n) (algoritmo voraz).
  • Aplicaciones: Selección de proyectos, carga de contenedores, empaquetado de recursos.
DP 0‑1 vs. Branch & Bound
  • Enfoque: Tabla completa vs. árbol de decisiones con poda.
  • Ventaja: DP garantiza solución óptima en tiempo predecible para W pequeño.
  • Ventaja de B&B: Escala mejor cuando W es enorme y los pesos son grandes.

8. Buenas prácticas y trucos de rendimiento

  • Ordenar por relación valor/peso: Útil antes de aplicar heurísticas o B&B.
  • Uso de numpy para la tabla: Operaciones vectorizadas pueden reducir el factor constante.
  • Memoria compartida en procesos paralelos: Cuando se evalúan múltiples instancias (ej. diferentes capacidades) se puede reutilizar la tabla parcial.
  • Limitar la capacidad: Redondear pesos a la unidad más grande que mantenga la precisión requerida reduce W y acelera DP.
import numpy as np
def knapsack_numpy(weights, values, capacity):
    dp = np.zeros(capacity + 1, dtype=int)
    for w, v in zip(weights, values):
        dp[w:] = np.maximum(dp[w:], dp[:-w] + v)
    return dp[capacity]

9. Depuración y troubleshooting comunes

ProblemaPosible causaSolución
Resultado negativoPesos o valores negativos en los datosValidar la entrada; filtrar o convertir a valores absolutos
Memoria agotadaCapacidad W demasiado grandeAplicar reducción de escala o usar algoritmo Branch & Bound
Ítems no coinciden con el valor óptimoBacktrack incorrecto (índice off‑by‑one)Revisar la lógica de recuperación, usar dp[i][c] != dp[i-1][c]

10. Extensiones y casos de uso reales

El algoritmo 0‑1 Knapsack aparece en:

  • Planificación de recursos en la nube: Asignar VMs a servidores físicos respetando límites de CPU y RAM.
  • Optimización de contenedores Docker/Podman: Seleccionar imágenes que maximizan funcionalidades dentro de un límite de tamaño de capa.
  • Selección de características en Machine Learning: Elegir subconjunto de variables que maximiza precisión bajo una restricción de coste computacional.

© 2025 BlogTech AI – Todos los derechos reservados.



Algoritmo del Problema de la Mochila 0-1: Conceptos, Implementación en Python y Mejores Prácticas
ASIMOV Ingeniería S. de R.L. de C.V., Emiliano Nava 15 noviembre, 2025
Compartir
Iniciar sesión dejar un comentario

  
Algoritmo de la Subseccuencia Creciente Más Larga (LIS) en Python: Guía Completa y Ejemplos Prácticos
Aprende a resolver el problema de la Subseccuencia Creciente Más Larga (LIS) con Python. Explicación teórica, implementaciones O(N²) y O(N log N), casos de uso, comparativas y buenas prácticas.