Dada uma lista de itens com peso e valor, e uma mochila com capacidade limitada, escolha quais itens levar para maximizar o valor total. Cada item só pode ser pego uma vez.
Diferente do Coin Change (1 dimensão), aqui temos dois eixos de variação: quais itens já considerei e quanta capacidade ainda tenho na mochila. Os dois precisam estar no estado.
Indexamos linhas pelos itens (0 = nenhum item, n = todos) e colunas pela capacidade restante (0 a W). Cada célula guarda o melhor valor possível dentro desses limites.
O problema da mochila 0/1 é um dos exemplos canônicos de DP em duas dimensões. Em cada célula dp[i][w], guardamos o melhor valor possível usando apenas os primeiros i itens com capacidade w disponível. Para cada item i e capacidade w, fazemos uma decisão binária: - skip: dp[i-1][w] (ignora o item) - take: dp[i-1][w - weight[i]] + value[i] (pega o item, se couber) A recorrência: dp[i][w] = max(skip, take). Construímos a tabela de cima pra baixo, da esquerda pra direita. Quando chegamos em dp[n][W], temos a resposta. Para descobrir QUAIS itens foram escolhidos, percorremos a tabela de volta: se dp[i][w] ≠ dp[i-1][w], o item i entrou na solução, então subtraímos seu peso e seguimos. A versão fracionária (Fractional Knapsack) tem solução gulosa O(n log n), mas a 0/1 não — daí a necessidade de DP.
“A "ordem dos itens" no array não importa para o valor final, mas a indexação por linha permite a recorrência. dp[i][w] sempre olha para a linha anterior — isso permite até reduzir espaço para O(W) com cuidado.”
n itens × W+1 capacidades. Cada célula é computada em O(1).
Tabela tem (n+1) × (W+1) células, cada uma O(1) → O(n × W)
Tabela 2D completa. Pode ser reduzida a O(W) iterando capacidade decrescente.
DP sempre preenche toda a tabela.
Mesma complexidade em qualquer entrada — independente dos valores.
| Algoritmo | Tempo | Espaco | Melhor Para |
|---|---|---|---|
| 0/1 Knapsack (DP)(atual) | O(n × W) | O(n × W) | Capacidade pequena/moderada, itens indivisíveis |
| Fractional Knapsack (Guloso) | O(n log n) | O(1) | Quando itens podem ser fracionados (ouro em pó, líquidos) |
| 0/1 Knapsack (Branch & Bound) | Exponencial pior caso | O(n) | Capacidade muito grande (W pseudo-polinomial) |
Pratique respondendo a perguntas comuns de entrevistas tecnicas. Clique em uma pergunta para iniciar uma sessao de pratica com IA.
1def knapsack(weights, values, capacity):Definição2 n = len(weights)3 dp = [[0] * (capacity + 1) for _ in range(n + 1)]Inicialização do DP4 5 for i in range(1, n + 1):Loop de Itens6 for w in range(capacity + 1):Loop de Capacidades7 if weights[i - 1] > w:Cabe na mochila?8 dp[i][w] = dp[i - 1][w]9 else:10 skip = dp[i - 1][w]11 take = dp[i - 1][w - weights[i - 1]] + values[i - 1]12 dp[i][w] = max(skip, take)Decisão Take vs Skip13 14 # Backtrack para reconstruir os itens15 chosen = []Backtrack16 i, w = n, capacity17 while i > 0:18 if dp[i][w] != dp[i - 1][w]:19 chosen.append(i - 1)20 w -= weights[i - 1]21 i -= 122 23 return dp[n][capacity], list(reversed(chosen))24