Mark mora em um pequeno país povoado por pessoas que tendem a pensar demais. Um dia, o rei do país decide redesenhar a moeda do país para tornar as trocas mais eficientes. O rei quer minimizar o número esperado de moedas necessárias para pagar exatamente qualquer quantia até (mas não incluindo) a quantia da menor nota de papel.
Suponha que a menor unidade de moeda seja a moeda. A menor nota de papel no reino vale a penaMoedas. O rei decide que não deve haver mais do quediferentes denominações de moedas em circulação. O problema, então, é encontrar um-conjunto de números inteiros de o que minimiza sujeito a .
Por exemplo, considere o dólar padrão e suas denominações de moedas de . Aqui, a menor conta de papel vale 100 da menor moeda. Leva 4 moedas para fazer 46 centavos usando esta moeda; temos. No entanto, se tivéssemos denominações de moedas de, seriam necessárias apenas 3 moedas: . Qual desses conjuntos de denominações minimiza o número médio de moedas para fazer qualquer soma até 99 centavos?
Mais geralmente, dado e , como alguém pode determinar algoritmicamente o conjunto ideal? Claramente, pode-se enumerar todos os-subsets e calcule o número médio de moedas necessárias para fazer somas de 1 a , acompanhando o melhor ao longo do caminho. Como existem cerca de -subsets (nem todos viáveis, mas ainda assim), isso não seria muito eficiente. Você pode fazer melhor que isso?
fonte
Respostas:
Isso está relacionado ao conhecido problema de mudança . Tão bem estudado, de fato, que esta questão foi investigada porm≤7 [1] usando força bruta. A partir de 2003, a dureza de encontrar denominações ótimas parece ser um problema em aberto.
Se você verificar os artigos que citam Shallit, parece que denominações que permitem estratégias gananciosas de mudança foram de particular interesse. É claro que essas denominações têm vantagens na prática.
fonte
Eu imaginei (erroneamente, mas tenha paciência comigo) que a série{bi| b=⌈n1/m⌉,0≤i<m} de moedas seria o ideal, pois as moedas seriam espaçadas exponencialmente, reduzindo assim o valor restante o máximo possível por moeda adicionada. Para o seu exemplo, isso seria{1,3,9,27,81} .
Este é um ponto melhor (390/99 ) que as denominações em USD (420/99 ), mas isso não precisa significar nada.
Escrevi um script hackeado de Haskell para obter alguns números por força bruta, pois não tenho certeza no momento de como abordar isso analiticamente.(m,n)=(4,30) Nós temos 75/29 para {20,8,3,1} mas 87/29 para {27,9,3,1} . Minha máquina lenta não consegue(5,100) , então temos que usar números menores aqui.
Acontece que a distribuição exponencial nem sempre é a melhor: às vezes há outras um pouco melhores, por exemplo, para
No entanto, notei que o erro parece ser bastante pequeno. Na maioria das vezes, a divisão das somas produz algo começando com um 1,0 ..., então eu fiz mais alguns testes.
De um conjunto de teste com3≤m≤5 e 6≤n≤40 , obtemos um erro médio de nosso crescimento exponencial em comparação com a melhor solução de 1.12 com um desvio padrão de 0.085 .
Você pode argumentar que os parâmetros de teste são bastante pequenos, mas, como você ressalta, é muita força bruta se você definirn=100 (provavelmente existe uma solução melhor, mas essa foi uma excelente desculpa para relaxar e fazer um pouco de Haskell).
Aqui está o meu conjunto de testes, se você quiser experimentá-lo:
Eu fiz o teste com
fonte