Lista de exercícios

Exercícios resolvidos: programação dinâmica no troco mínimo

Desafios sobre subproblemas repetidos, estado, transição, tabulação, memoização, reconstrução e custo no troco mínimo.

Uma máquina de fichas de uma convenção de jogos ejeta uma ficha por vez. Para atender cada pedido mais rápido, ela precisa formar o valor exato com o menor número de fichas. Os valores disponíveis mudam entre os desafios. Cada enunciado informa os dados necessários, e não é preciso conhecer a convenção.

Resolva um exercício por vez e abra a solução para conferir. Não há entrega nem nota. Resposta esperada é um modelo para comparação e autocorreção. Os exercícios são independentes, exceto quando um enunciado declarar uma sequência cumulativa.

Exercício 1: a escolha mais rápida sempre vence?

Teste a regra gulosa de pegar a maior ficha que cabe. Uma máquina dispõe de fichas de valores 1, 4 e 5, sem limite de quantidade, e deve entregar exatamente 8 unidades. Compare a entrega produzida pela regra com a menor quantidade possível de fichas. Justifique por que sua alternativa é ótima.

Solução

Explicação

A regra pega 5 primeiro e só consegue completar o restante 3 com fichas de 1. Uma alternativa com duas fichas de 4 reduz a quantidade. Não há ficha de valor 8, então uma solução com apenas uma ficha não existe.

Objetivo de aprendizagem: encontrar um contraexemplo para decidir quando a escolha local não serve como método de solução.

Resposta esperada

A regra gulosa entrega 5 + 1 + 1 + 1, com quatro fichas. A entrega 4 + 4 usa duas fichas e forma exatamente 8. Como não existe ficha de valor 8, duas é a quantidade mínima.

Exercício 2: caminhos diferentes repetem o mesmo trabalho?

Compare as perguntas restantes numa busca por fichas de valores 1, 3 e 4, com quantidade ilimitada. O pedido é de 7 unidades. Em cada caminho abaixo, as fichas indicadas já foram retiradas do valor solicitado:

  1. Primeiro 1, depois 3.
  2. Primeiro 3, depois 1.
  3. Uma ficha de 4.

Em cada caso, indique o valor que falta formar. Diga se a resposta sobre esse valor pode ser calculada uma vez e reutilizada nos três caminhos.

Solução

Explicação

As três sequências retiram 4 unidades do pedido. Como o estoque é ilimitado, os caminhos deixam exatamente os mesmos tipos de ficha disponíveis. A quantidade de fichas já usadas difere, mas a melhor resposta para o restante é a mesma.

Objetivo de aprendizagem: identificar subproblemas sobrepostos pela pergunta que permanece para evitar recalcular a mesma resposta.

Resposta esperada

Todos os caminhos deixam 3 unidades para formar: 7 - 1 - 3 = 3, 7 - 3 - 1 = 3 e 7 - 4 = 3. A menor quantidade de fichas para esse restante pode ser calculada uma vez e reutilizada. Os totais dos caminhos completos ainda somam as fichas já usadas em cada um.

Exercício 3: uma entrega ótima pode usar um restante ruim?

Corrija um plano para entregar 11 unidades com fichas de valores 1, 3 e 5, em quantidade ilimitada. O plano termina com uma ficha de 1 e usa 5 + 3 + 1 + 1 para formar as 10 unidades anteriores. Compare esse restante com 5 + 5 e explique o que a troca demonstra sobre qualquer entrega ótima que termine com 1.

Solução

Explicação

As duas formas produzem o mesmo restante de 10. Substituir quatro fichas por duas mantém a soma e reduz a quantidade da entrega completa. Logo, uma entrega ótima não pode conservar um restante que admite uma solução melhor.

Objetivo de aprendizagem: justificar por substituição por que a solução ótima pode usar a melhor resposta para um valor restante.

Resposta esperada

O plano original é 5 + 3 + 1 + 1 + 1, com cinco fichas. Substituir o restante por 5 + 5 produz 5 + 5 + 1, com três fichas. Portanto, se uma entrega ótima termina com 1, as outras fichas precisam formar as 10 unidades restantes com a menor quantidade possível.

Exercício 4: zero fichas ou valor impossível?

Defina o estado F(value) para uma máquina que deve formar um valor exato com o menor número de fichas. Use fichas de valores 3 e 4, em quantidade ilimitada. Indique o que F(0), F(1) e F(2) devem registrar e explique por que o caso base e um valor impossível não podem receber o mesmo marcador.

Solução

Explicação

O estado responde uma quantidade mínima, não uma lista de fichas. Para formar zero, a entrega vazia é válida e custa zero. Já 1 e 2 não podem ser formados com fichas de 3 e 4. Um marcador como ∞ separa impossibilidade do custo válido zero.

Objetivo de aprendizagem: definir o estado e distinguir caso base de impossibilidade para que a tabela represente respostas corretas.

Resposta esperada

F(value) é a menor quantidade de fichas que forma exatamente value. Temos F(0) = 0, F(1) = ∞ e F(2) = ∞. O zero significa uma entrega válida sem fichas; ∞ significa que nenhuma entrega forma o valor.

Exercício 5: qual última ficha fica registrada?

Calcule a melhor decisão para formar 7 unidades com fichas coins = [3, 4], em quantidade ilimitada. São conhecidos F(3) = 1 e F(4) = 1. Para cada possível última ficha, calcule a quantidade total, determine F(7) e registre em last_coin[7] o índice da ficha escolhida. Teste o índice 0 antes do 1 e conserve a primeira escolha em caso de empate.

Solução

Explicação

A última ficha acrescenta uma unidade à quantidade de fichas necessária para o restante. As duas escolhas produzem o mesmo custo. Como o empate não substitui a decisão anterior, fica registrado o índice da ficha testada primeiro.

Objetivo de aprendizagem: aplicar a transição do troco mínimo e registrar uma decisão que permita reconstruir a entrega.

Resposta esperada

Última fichaRestanteQuantidade total
3, índice 041 + F(4) = 2
4, índice 131 + F(3) = 2

Assim, F(7) = 2 e last_coin[7] = 0. O índice 0 identifica a ficha de valor 3.

Exercício 6: três linhas bastam para testar a tabela

Complete três estados consecutivos de uma tabulação com fichas coins = [2, 5], em quantidade ilimitada. F(value) é a menor quantidade para formar exatamente value. Os estados necessários já estão prontos:

Valor12345
F(value)∞1∞21

Calcule F(6), F(7) e F(8) nessa ordem. Para cada valor, registre o índice da última ficha em last_coin[value]. Teste a ficha 2 antes da 5 e mantenha a primeira decisão nos empates.

Solução

Explicação

Cada linha usa somente restos menores já resolvidos. Um resto impossível não produz candidata. Em 7, as duas últimas fichas possíveis geram a mesma quantidade, então o índice 0 permanece.

Objetivo de aprendizagem: avançar na tabulação sem consultar respostas futuras e registrar empates de modo reproduzível.

Resposta esperada

ValorCandidata com 2Candidata com 5F(value)last_coin[value]
61 + F(4) = 3Resto 1 impossível30
71 + F(5) = 21 + F(2) = 220
81 + F(6) = 4Resto 3 impossível40

Exercício 7: o índice entrega qual ficha?

Reconstrua uma entrega de 11 unidades com coins = [3, 5]. O vetor last_coin guarda o índice da última ficha escolhida em cada valor. São conhecidos last_coin[11] = 0, last_coin[8] = 0 e last_coin[5] = 1. Comece com restante 11. Em cada passo, registre o índice consultado, a ficha recuperada e o novo restante. Confira a soma e a quantidade ao chegar a zero.

Solução

Explicação

O índice localiza uma posição em coins. O valor nominal dessa posição é subtraído do restante. Cada ficha positiva diminui o restante, e a sequência termina quando ele chega a zero.

Objetivo de aprendizagem: reconstruir uma entrega a partir das decisões guardadas sem confundir índice com valor nominal.

Resposta esperada

Restante antesÍndiceFichaRestante depois
11038
8035
5150

A entrega é 3 + 3 + 5 = 11, com três fichas.

Exercício 8: por que a tabela não sai do zero?

Diagnostique uma inicialização de tabulação. Uma máquina usa fichas de valores 3 e 4 para formar valores exatos. O caso base está correto, mas o programa inicia todas as demais posições com zero. Depois, só substitui uma posição quando encontra uma quantidade de fichas menor que o valor guardado.

Mostre o que acontece ao avaliar o valor 3 e corrija a representação inicial dos estados ainda sem solução.

Solução

Explicação

Formar 3 com uma ficha produz a candidata 1. Como 1 não é menor que o zero indevidamente armazenado em F(3), a atualização não acontece. Zero deve ficar reservado ao caso base; as demais posições começam com um marcador que não se confunde com custo válido.

Objetivo de aprendizagem: detectar como uma representação incorreta impede atualizações válidas e separar custo zero de impossibilidade.

Resposta esperada

A candidata para F(3) é 1, mas a comparação 1 < 0 é falsa. O programa mantém incorretamente F(3) = 0. A correção é reservar zero ao caso base e iniciar as demais posições com um marcador de impossibilidade, como ∞. Antes de somar 1 a um resto, é preciso verificar se ele não está marcado como impossível.

Exercício 9: uma resposta pode ser usada antes de existir?

Verifique a ordem de um plano de tabulação para fichas positivas de valores 3 e 4. O caso base F(0) já está pronto. O plano tenta calcular F(7) antes de qualquer outro estado não base. Cada candidata consulta F(value - coin).

Quais estados F(7) precisaria consultar? Indique uma ordem de preenchimento que garanta que todas as dependências de cada estado já estejam prontas.

Solução

Explicação

As fichas 3 e 4 deixam restos 4 e 3. Nenhum deles foi calculado no plano proposto. Como cada ficha é positiva, toda dependência tem valor menor que o estado atual. Avançar a partir do caso base respeita essa direção.

Objetivo de aprendizagem: escolher uma ordem de tabulação que respeite as dependências e evite consultar respostas futuras.

Resposta esperada

F(7) precisaria de F(4) e F(3), ainda ausentes. O plano deve preencher os valores em ordem crescente, começando em F(1) após o caso base e seguindo até F(7). Estados impossíveis também recebem uma resposta definitiva antes de serem consultados.

Exercício 10: quando a resposta entra no cache?

Rastreie a memoização para fichas [2, 3] e pedido 7. A função recursiva tenta primeiro a ficha 2 e depois a 3, ignorando fichas maiores que o valor restante. O cache começa apenas com o caso base pronto. Cada F(value) é guardado só depois de testar todas as suas candidatas, inclusive quando é impossível.

Registre a ordem em que os estados não base recebem respostas definitivas. Indique o primeiro estado não base que volta a ser consultado depois de já estar no cache.

Solução

Explicação

As primeiras chamadas descem por 7 → 5 → 3 → 1. O estado 1 é impossível e recebe essa resposta no cache. A função só guarda F(3) após conferir as duas fichas. Mais tarde, o cálculo de F(4) encontra F(2) já pronto.

Objetivo de aprendizagem: distinguir chamada, conclusão e reutilização de estados para rastrear corretamente o cache recursivo.

Resposta esperada

Os estados não base entram no cache nesta ordem: F(1), F(3), F(2), F(5), F(4), F(7). F(1) é armazenado como impossível. O primeiro acerto de cache não base é F(2), consultado durante o cálculo de F(4).

Exercício 11: começar pelo pedido ou pela tabela?

Escolha entre memoização e tabulação para duas necessidades independentes de um sistema de fichas:

  1. Antes de abrir, um painel precisa das respostas para todos os pedidos de 0 a 100.
  2. Uma consulta isolada pede 120 unidades com fichas de valores 40 e 60, em quantidade ilimitada.

Em cada caso, justifique a escolha pela ordem de cálculo e pelos estados efetivamente resolvidos. Considere que a memoização usa um vetor de cache para todo o intervalo e uma pilha recursiva.

Solução

Explicação

As duas técnicas reutilizam respostas. A tabulação começa no caso base e preenche a faixa planejada. A memoização começa no pedido e só resolve estados alcançados, embora o vetor de cache ainda reserve posições para todo o intervalo.

Objetivo de aprendizagem: escolher entre memoização e tabulação pelo padrão de consultas, considerando cálculo e memória reservada.

Resposta esperada

  1. Tabulação: calcula todos os valores de 0 a 100 em ordem crescente, exatamente o que o painel precisa, sem pilha recursiva.
  2. Memoização: a partir de 120, só precisa resolver os valores 120, 80, 60, 40, 20 e 0. O vetor de cache ainda reserva posições de 0 a 120 e a recursão usa pilha.

Exercício 12: a tabela cabe no equipamento?

Estime os recursos de uma tabulação para valor solicitado 500.000 e seis tipos de ficha. O algoritmo guarda duas tabelas com amount + 1 elementos cada, testa os seis tipos em todo estado não base e usa 8 bytes por elemento. O dispositivo reserva 7.500.000 bytes para essas tabelas. Desconsidere a saída reconstruída e outras estruturas.

Calcule o número de estados, o total de testes de ficha e os bytes das duas tabelas. Decida se elas cabem no espaço reservado.

Solução

Explicação

Há uma posição para cada valor de zero ao pedido. Os testes ocorrem nos estados não base. As duas tabelas têm o mesmo comprimento. A comparação com o orçamento considera bytes, sem arredondar para megabytes.

Objetivo de aprendizagem: estimar trabalho e memória da tabulação para decidir se ela cabe nos recursos disponíveis.

Resposta esperada

São 500.001 estados, 3.000.000 testes de ficha e 8.000.016 bytes nas duas tabelas: 2 × 500.001 × 8. Elas não cabem nos 7.500.000 bytes reservados. Faltam 500.016 bytes. O tempo é O(amount × coin_count) e o espaço das tabelas é O(amount).

Exercício 13: um número curto pode exigir uma tabela enorme?

Este exercício é opcional. Explique o custo pseudopolinomial de uma tabulação que cria amount + 1 estados e testa coin_count tipos por estado. Considere amount = 1.000.000, representável com cerca de 20 bits, pois 2^20 = 1.048.576. Relacione o tempo O(amount × coin_count) com a quantidade de bits usada para escrever amount.

Solução

Explicação

O algoritmo percorre valores numéricos até um milhão, apesar de esse número caber em aproximadamente 20 bits. Em geral, b bits podem representar valores próximos de 2^b; a tabela pode crescer exponencialmente em relação a b.

Objetivo de aprendizagem: distinguir custo no valor numérico e no tamanho da entrada para reconhecer o limite pseudopolinomial.

Resposta esperada

O tempo é polinomial em amount, mas pode ser exponencial na quantidade de bits que representa esse número. Para um valor com b bits, amount pode ser da ordem de 2^b. Por isso, O(amount × coin_count) é chamado de pseudopolinomial.

Exercício 14: atualizar custo e escolha em C

Escreva um trecho em C17 para atualizar um estado do troco mínimo. Uma moeda que cabe já foi selecionada. previous contém o custo mínimo do restante ou SIZE_MAX quando ele é impossível. SIZE_MAX é o maior valor representável por size_t e serve como marcador de impossibilidade. best é o menor custo encontrado até agora, chosen_index guarda o índice da moeda dessa escolha e coin_index é o índice da moeda em teste. Qualquer custo válido após somar 1 é menor que SIZE_MAX.

Ignore o resto impossível. Se a nova candidata for estritamente menor que best, atualize best e chosen_index. Escreva somente esse trecho, com comentários didáticos em PT-BR antes de cada decisão.

Solução

Explicação

O marcador de impossibilidade não pode participar da soma. Uma candidata válida acrescenta uma moeda ao custo do restante. A comparação estrita preserva a primeira escolha quando há empate e mantém custo e índice coerentes.

Objetivo de aprendizagem: atualizar custo e escolha em C sem somar ao marcador de impossibilidade nem registrar um empate como melhora.

Resposta esperada

// Apenas um restante possível produz uma candidata.
if (previous != SIZE_MAX) {
    size_t candidate = previous + 1U;

    // Atualize custo e índice somente quando a candidata melhorar.
    if (candidate < best) {
        best = candidate;
        chosen_index = coin_index;
    }
}

Exercício 15: o mesmo valor restante ainda é o mesmo estado?

Este exercício é opcional. Compare dois estados parciais de uma máquina com estoque limitado. Ela possui uma ficha de valor 2, duas de valor 3 e uma de valor 4. O pedido é de 10 unidades.

  • Caminho A: já foram escolhidas as duas fichas de 3.
  • Caminho B: já foram escolhidas as fichas de 2 e de 4.

Os dois caminhos deixam o mesmo valor por formar. Determine se eles ainda fazem o mesmo subproblema. Indique quais informações precisam compor o estado para que uma resposta guardada possa ser reutilizada com segurança.

Solução

Explicação

Ambos os caminhos já usam 6 unidades e deixam 4. No caminho A, a ficha de 4 continua disponível. No caminho B, ela e a ficha de 2 foram consumidas, restando somente fichas de 3. O mesmo valor restante pode ter respostas diferentes.

Objetivo de aprendizagem: ampliar o estado quando o estoque altera a resposta para o mesmo valor restante e evitar reutilização incorreta.

Resposta esperada

Os caminhos não representam o mesmo subproblema. Ambos deixam 4 unidades, mas A ainda dispõe da ficha de 4 e pode concluir a entrega; B dispõe apenas de duas fichas de 3 e não consegue formar 4. O estado precisa registrar o valor restante e o estoque remanescente de cada tipo de ficha. Guardar a resposta apenas por valor restante misturaria situações diferentes.