Solução Em Busca do Corpo Perfeito

Solução por Rogério Júnior

Infelizmente, um algoritmo guloso que sempre come o pedaço com maior valor proteico ou com maior percentual de proteína acaba errando. O problema é uma adaptação de um clássico algoritmo chamado knapsack. É muito importante entendê-lo e saber implementá-lo antes de fazer qualquer competição de programação. Se você não o conhece, clique aqui para ver a aula do Curso Noic de Informática sobre Programação Dinâmica. A abordagem estilo top-down, que acaba sendo mais rápida neste caso, usa uma função recursiva que verifica, para cada objeto, se devemos colocá-lo ou não na mochila, ou no caso, se devemos comer ou não o pedaço de carne. A implementação é muito simples e usa uma função que já retorna o máximo de proteína que nosso físico pode comer, que chamaremos knapsack. Ela receberá como parâmetros o int pedaco, que será o pedaço de carne que vamos analisar se comeremos ou não e o int espaco que representa quanto espaço ainda há na barriga de Kakariús, ou seja, quantos gramas de carne ele ainda pode comer. A solução é melhor explicada direto no comentário do código:


#include <cstdio> // printf e scanf
#include <cstring> // memset
#define MAX 2200 // limite de N e P
int max(int a, int b){ // função max, usada no knapsack, retorna o maior dentre dois números
if(a>b) return a;
return b;
}
int n, p, peso[MAX], prot[MAX]; // declaração de variáveis
int tab[MAX][MAX]; // tabela de pd
int knapsack(int pedaco, int espaco){ // função do knapsack recebe o pedaço que vou analisar (pedaco) e quanto ainda posso comer (espaco)
if(tab[pedaco][espaco]>=0) return tab[pedaco][espaco]; // se já calculei o valor da função para esses parâmetros, retorn ele
if(pedaco>n) return tab[pedaco][espaco]=0; // se já analisei todos os pedaços, retorn 0
int come; // o quanto ganho se comer o pedaço
// se poder comê-lo, ganho seu valor, mais o melhor entre comer ou não o próximo
if(peso[pedaco]<=espaco) come=prot[pedaco]+knapsack(pedaco+1, espaco-peso[pedaco]);
else come=0; // se não tiver mais espaço para comê-lo, faça a variável come receber zero
int nao_come=knapsack(pedaco+1, espaco); // não comer o pedaço me dará apenas o melhor entre comer ou não o próximo
return tab[pedaco][espaco]=max(come, nao_come); // devo retornar o melhor entre comer ou não o pedaço
}
int main(){
scanf("%d %d", &p, &n); // leio o valor de P e N
memset(tab, -1, sizeof(tab)); // marco todos os valores da tabela como "não calculados"
for(int i=1; i<=n; i++) scanf("%d %d", &peso[i], &prot[i]); // leio o peso e valor de cada pedaço
printf("%d\n", knapsack(1, p)); // imprimo o valor de knapsack começando do objeto 1 e com todo o espaço que Kakariús aguenta
return 0;
}

view raw

knapsack.cpp

hosted with ❤ by GitHub