Introdução
Seja você um aspirante a programador, um estudante de ciência da computação, ou simplesmente alguém curioso sobre algoritmos, já ouviu falar de um dos dilemas mais conhecidos na área de computação: O problema da mochila. Este artigo não só introduzirá você a esse desafio intrigante mas também o conduzirá através da elegante solução que a programação dinâmica oferece. Vamos lá!
Entendendo o Problema
O Problema da Mochila, conhecido em inglês como “knapsack problem(0/1)”, é um desafio de otimização que encontra paralelos em cenários do cotidiano. Visualize-se com uma mochila que tem a capacidade limitada a 3 kg. À sua disposição, uma variedade de objetos, cada um com seu respectivo peso e valor. O seu desafio é determinar a combinação ótima desses objetos que, ao serem colocados na mochila, maximizem o valor total sem ultrapassar o limite de peso estabelecido.
Dentre as suas várias versões, destaca-se a variante 0/1, que impõe uma condição singular: cada item disponível pode ser escolhido apenas uma vez. É com essa restrição específica que guiaremos nossa exploração no decorrer deste artigo.
Exemplo
Considere o seguinte cenário: você tem à disposição os itens listados abaixo. O objetivo é selecionar a combinação que, somada, ofereça o maior valor, sem exceder a capacidade de peso da sua mochila.

Considere que o primeiro item a ser selecionado é o tablet, com peso leve de 1 kg e um valor estimado de R$ 100,00. Ele se encaixa perfeitamente na mochila, deixando ainda espaço suficiente para adicionar outros itens, desde que o peso total desses itens adicionais não exceda 2 kg.

Avançando para o segundo item, um relógio que pesa 2.5 kg e vale R$ 80,00. A soma dos pesos dos dois itens excede o limite de 3 kg da mochila, impossibilitando o transporte simultâneo de ambos. Neste cenário, é mais estratégico manter o tablet, visto que o valor do segundo item é inferior ao do primeiro.
Prossigamos, então, com o terceiro item: um videogame que pesa 2 kg e possui um valor significativo de R$ 200,00. Com o tablet já posicionado na mochila, pesando somente 1 kg, há espaço suficiente para incluir o videogame e ainda permanecer dentro do limite de peso de 3 kg. A adição deste novo item eleva o valor total dos conteúdos a R$ 300,00. A combinação do tablet e videogame não só aproveita eficientemente o espaço disponível como também maximiza o valor transportado, respeitando o peso máximo permitido.

Exemplo Realista
O Problema da Mochila também encontra sua utilidade em cenários financeiros, onde, por exemplo, uma pessoa ou empresa precisa maximizar o valor das compras dentro de um orçamento limitado. Cada item disponível no mercado possui um custo e um valor potencial agregado. Nesse contexto, o desafio se assemelha ao de encher uma mochila: é necessário escolher uma combinação de itens que traga o maior retorno possível em termos de valor, sem exceder a restrição do orçamento estabelecido.
Solução
Programação Dinâmica no Contexto do Problema da Mochila
Programação dinâmica é uma técnica que constrói a solução de problemas complexos a partir da resolução de subproblemas menores, evitando o retrabalho ao armazenar estas soluções parciais. No âmbito do Problema da Mochila 0/1, utilizamos essa metodologia para determinar a configuração ótima de itens, maximizando o valor dentro do limite de peso. O foco deste artigo não é aprofundar-se nos meandros teóricos da programação dinâmica, mas sim demonstrar sua aplicação prática na obtenção da melhor solução para nosso problema específico.
Algoritmo
Para simplificar, consideremos uma situação em que possuímos uma mochila com capacidade de 10 kg e uma lista de itens representados por pares de números: [1,2],[4,3],[5,6],[6,7]. No par, o primeiro número representa o valor do item, enquanto o segundo indica seu peso. Com base nesse exemplo, vamos desenvolver um algoritmo.
Logo abaixo, você encontrará o código utilizado para resolver o exemplo acima. Entendemos que alguns conceitos podem ser complexos e talvez não fiquem imediatamente claros apenas pela escrita. Por isso, preparamos um vídeo detalhado onde explicamos o algoritmo passo a passo. Para uma compreensão mais aprofundada e visual do processo, basta clicar no link abaixo e mergulhar na lógica por trás da programação dinâmica aplicada a este problema.
Análise da Complexidade
A complexidade de tempo do algoritmo para o Problema da Mochila utilizando programação dinâmica para o é O(nW), onde O(nW), onde n é o número de itens a escolher e W é a capacidade total de peso da mochila. Isso significa que o tempo necessário para encontrar a solução cresce proporcionalmente ao número de itens e ao peso máximo que a mochila pode carregar.
Em relação à complexidade de espaço, ela também é O(nW), pois precisamos de um espaço de memória para armazenar o valor máximo possível para cada combinação de itens e capacidades de peso. Em outras palavras, para cada item, armazenamos o melhor valor que podemos obter sem exceder cada peso incremental até o peso máximo W.
Portanto, quanto maior o número de itens e maior a capacidade da mochila, mais tempo e memória o computador precisará para resolver o problema.
Implementação
public static List<List<Integer>> problemaMochila(int[][] itens, int capacidadeMochila) {
List<List<Integer>> resultado = new ArrayList<>();
int[][] itensMochila = new int[itens.length + 1][capacidadeMochila + 1];
for (int linha = 1; linha < itensMochila.length; linha++) {
int valorItemAtual = itens[linha - 1][0];
int pesoItemAtual = itens[linha - 1][1];
for (int coluna = 0; coluna < itensMochila[linha].length; coluna++) {
int capacidadeMochilaAtual = coluna;
if (capacidadeMochilaAtual < pesoItemAtual) {
itensMochila[linha][coluna] = itensMochila[linha - 1][coluna];
} else {
int capacidadeRestante = capacidadeMochilaAtual - pesoItemAtual;
int valorAgregadoCapacidadeRestante = itensMochila[linha - 1][capacidadeRestante];
int valorAtualizado = valorItemAtual + valorAgregadoCapacidadeRestante;
itensMochila[linha][coluna] = Math.max(valorAtualizado, itensMochila[linha - 1][coluna]);
}
}
}
int linha = itensMochila.length - 1;
int coluna = itensMochila[linha].length - 1;
int valorAgregado = itensMochila[linha][coluna];
resultado.add(Arrays.asList(valorAgregado));
resultado.add(new ArrayList<>());
while (valorAgregado > 0) {
if (valorAgregado == itensMochila[linha - 1][coluna]) {
linha--;
} else {
resultado.get(1).add(linha - 1);
int capacidadeAtual = coluna;
int capacidadeRestante = capacidadeAtual - itens[linha - 1][1];
coluna = capacidadeRestante;
linha--;
}
valorAgregado = itensMochila[linha][coluna];
}
System.out.println(Arrays.deepToString(itensMochila));
return resultado;
} Conclusão
Chegamos ao fim de nossa exploração do Problema da Mochila, um desafio clássico que põe à prova nossa habilidade de maximizar valor dentro de limites definidos. Ao longo deste artigo, desdobramos o problema em seus componentes básicos, exploramos a metodologia da programação dinâmica e aplicamos conceitos teóricos a exemplos práticos. Demonstramos como, com um número finito de itens e uma capacidade de peso definida, podemos utilizar o algoritmo de programação dinâmica para encontrar a combinação ideal que maximiza o valor na mochila.
Entendemos que a complexidade de tempo e espaço do algoritmo é �(��)O(nW), onde �n é o número de itens e �W a capacidade máxima de peso da mochila. Embora possa ser desafiador para casos com muitos itens ou para mochilas de grande capacidade, a programação dinâmica se mostra uma ferramenta eficaz e poderosa.
Este conhecimento não é apenas uma peça teórica de inteligência computacional; ele tem aplicações práticas em diversas áreas, desde restrições financeiras na seleção de investimentos até a otimização de recursos em logística e planejamento. A habilidade de tomar decisões estratégicas, ponderando entre várias opções sob restrições, é uma habilidade valiosa no mundo da programação e além.
Esperamos que este artigo tenha iluminado o caminho para uma compreensão mais profunda do Problema da Mochila e que o conhecimento adquirido aqui seja uma adição valiosa ao seu conjunto de ferramentas analíticas. À medida que você continua a jornada de aprendizado em algoritmos e programação, lembre-se que cada problema é uma oportunidade para crescer e que as soluções estão apenas à espera de serem descobertas.
Deixe um comentário abaixo com suas dúvidas ou insights. Vamos aprender juntos!