Enumeração de problemas de mudança de moeda usando N moedas e cada denominação

13

O problema de troca de moedas está muito bem documentado. Dada uma fonte infinita de moedas de denominações x_1para x_mvocê precisa encontrar o número de combinações que somam y. Por exemplo, dado x = {1,2,3}e y = 4temos quatro combinações:

  1. {1,1,1,1}
  2. {1,1,2}
  3. {1,3}
  4. {2,2}

Introdução

Existem várias variações do problema de troca de moedas. Nesta variação, temos duas restrições adicionais:

  1. Toda denominação deve ser usada pelo menos uma vez.
  2. Exatamente um número fixo de moedas deve ser usado no total.

Por exemplo, dada x = {1,2,3}, y = 36e n = 15onde né o número total de moedas que devem ser usados, temos quatro combinações:

  1. {1,2,2,2,2,2,2,2,3,3,3,3,3,3,3} (1, 7, 7)
  2. {1,1,2,2,2,2,2,3,3,3,3,3,3,3,3} (2, 5, 8)
  3. {1,1,1,2,2,2,3,3,3,3,3,3,3,3,3} (3, 3, 9)
  4. {1,1,1,1,2,3,3,3,3,3,3,3,3,3,3} (4, 1, 2, 3)

Desafio

O desafio é escrever uma função enumerateno idioma de sua escolha que enumere todas as combinações conforme descrito acima:

  1. A lista de denominações. Por exemplo {1,5,10,25}. Você pode usar listas ou matrizes.
  2. Um número inteiro não negativo yque indica a soma de todas as combinações.
  3. Um número inteiro não negativo nque indica o número total de moedas.

A ordem dos argumentos não importa. Funções pointfree são permitidas.

A saída da enumeratefunção deve ser uma lista de combinações. Cada combinação deve ser única e deve ser uma lista de nnúmeros inteiros que somam y. Toda denominação deve aparecer pelo menos uma vez em cada combinação e nenhuma combinação deve estar faltando. A ordem dos números inteiros e as combinações não importa. Você pode usar listas ou matrizes para a saída.

Lembre-se dos seguintes casos extremos:

  1. Se ambos ye nsão iguais a zero e a lista de denominações está vazia, então a saída é uma lista de uma combinação, a combinação vazio (ou seja {{}}).
  2. Caso contrário, se yfor zero, nfor zero ou a lista de denominações estiver vazia, a saída será uma lista de combinações zero (ou seja {}).
  3. De um modo mais geral, se yfor menor que a soma das denominações ou nmenor que o número de denominações, a saída será uma lista de combinações zero.

A pontuação será baseada no tamanho do programa inteiro em bytes. Observe que isso inclui a enumeratefunção, funções auxiliares, instruções de importação, etc. Não inclui casos de teste.

Aadit M Shah
fonte
Tenho certeza de que já vi esse desafio em algum lugar ... #
Leaky Nun
Espero que esta pergunta não seja duplicada. Não consegui encontrar a mesma pergunta no Code Golf. Por isso, eu postei.
Aadit M Shah
@PeterTaylor Se yfor menor que a soma das denominações, em algum momento da sua solução recursiva, você alcançará o caso base em que a lista de denominações está vazia. Portanto, a resposta será {}(ou seja, nenhuma solução encontrada). Se nfor menor que o número de denominações, você finalmente alcançará o caso base onde n = 0mas y != 0. Portanto, a resposta será novamente {}.
Aadit M Shah
@PeterTaylor Indeed. Eu poderia ter assumido muito sobre os detalhes da implementação. Você saberia como consertar isso?
Aadit M Shah
10
Sugiro que você remova o sinalizador "Aceito" até obter uma resposta útil. E, em geral, é sensato esperar alguns dias antes de aceitar.
Peter Taylor

Respostas:

2

05AB1E, 20 bytes

g-¹sã€{Ùvy¹«DO³Qiˆ}¯

A entrada é na ordem: list of values, nr of coins, sum to reach.

Explicação resumida

  1. Obtenha todas as permutações da lista de moedas de comprimento: final length - length of unique coin list
  2. Adicione a lista de moedas exclusivas a essas listas.
  3. Se a soma for igual à soma procurada, salve a lista
  4. Saída de todas as listas salvas

Experimente online

O compilador online não pode lidar com um grande número de moedas.

Emigna
fonte
4

MATL , 22 bytes

Z^!S!Xu!tsi=Z)"1G@m?@!

A ordem de entrada é: matriz de denominações, número de moedas retiradas ( n), soma desejada ( y).

Cada combinação é exibida em uma linha diferente. Saída vazia é exibida como uma sequência vazia (então nada).

Experimente online!

O código fica sem memória no compilador online, por exemplo, no desafio, mas funciona offline com um computador padrão e razoavelmente moderno:

>> matl
 > Z^!S!Xu!tsi=Z)"1G@m?@!
 > 
> [1 2 3]
> 15
> 36
1 1 1 1 2 3 3 3 3 3 3 3 3 3 3
1 1 1 2 2 2 3 3 3 3 3 3 3 3 3
1 1 2 2 2 2 2 3 3 3 3 3 3 3 3
1 2 2 2 2 2 2 2 3 3 3 3 3 3 3

Explicação

Z^      % Implicitly input array of denomminations and number of coins n. Compute 
        % Cartesian power. This gives 2D array with each "combination"
        % on a different row
!S!     % Sort each row
Xu      % Deduplicate rows
!       % Transpose: rows become columns. Call this array A
ts      % Push a copy, compute sum of each column
i       % Input y (desired sum)
=       % Logical array that contains true if the "combination" has the desired sum
Z)      % Keep only those columns in array A
"       % For each column
  1G    %   Push array of denominations again
  @     %   Push current column
  m     %   Is each denomination present in the column?
  ?     %   If so
    @!  %     Push current column again. Transpose into a row
        %   End if
        % End for
        % Implicitly display stack contents
Luis Mendo
fonte
3

Python 3, 120 106 bytes

from itertools import*
lambda d,t,l:[i+d for i in combinations_with_replacement(d,l-len(d))if sum(i+d)==t]

Uma função anônima que recebe uma tupla de denominações do formulário (x_1, x_2, x_3 ... , x_k), um valor de destino e um número de moedas via argumento e retorna uma lista de tuplas do formulário [(solution_1), (solution_2), (solution_3), ... (solution_k)].

Como funciona

ItertoolsA combinations_with_replacementfunção de é usada para gerar todas as l-len(d)combinações, com substituição, das denominações. Ao anexar da cada uma dessas combinações, é garantido que cada denominação apareça pelo menos uma vez e que a nova combinação tenha comprimento l. Se os elementos de uma combinação somarem t, a combinação será adicionada à lista de retorno como uma tupla.

Experimente no Ideone


Um método alternativo para 108 bytes

from itertools import*
lambda d,t,l:set(tuple(sorted(i+d))for i in product(d,repeat=l-len(d))if sum(i+d)==t)

Função anônima que recebe entrada de uma tupla de denominações do formulário (x_1, x_2, x_3 ... , x_k), um valor de destino e um número de moedas via argumento e retorna um conjunto de tuplas do formulário {(solution_1), (solution_2), (solution_3), ... (solution_k)}.

Como funciona (outra versão)

Isso usa a productfunção deitertools para gerar todos os l-len(d)arranjos das denominações. Ao anexar da cada uma dessas combinações, é garantido que cada denominação apareça pelo menos uma vez e que a nova combinação tenha comprimento l. Se os elementos de uma combinação somam t, a combinação é classificada, convertida de uma lista em uma tupla e adicionada às tuplas de retorno. Por fim, a chamada setremove as duplicatas.

Experimente no Ideone (outra versão)

TheBikingViking
fonte
0

JavaScript (ES6), 135 bytes

g=(a,n,y,r)=>n>0?y>0&&a.map((x,i)=>g(a.slice(i),n-1,y-x,[...r,x])):n|y||console.log(r)
(a,n,y)=>g(a,n-a.length,a.reduce((y,x)=>y-x,y),a)
Neil
fonte