Enumeración del problema de cambio de monedas usando N monedas y cada denominación

13

El problema del cambio de monedas está muy bien documentado. Dado un suministro infinito de monedas de denominaciones x_1que x_mes necesario encontrar el número de combinaciones que suman y. Por ejemplo, dado x = {1,2,3}y y = 4tenemos cuatro combinaciones:

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

Introducción

Hay varias variaciones del problema del cambio de monedas. En esta variación tenemos dos restricciones adicionales:

  1. Cada denominación debe usarse al menos una vez.
  2. Se debe usar exactamente un número fijo de monedas en total.

Por ejemplo, dado x = {1,2,3}, y = 36y n = 15dónde nestá el número total de monedas que se deben usar, obtenemos cuatro combinaciones:

  1. {1,2,2,2,2,2,2,2,3,3,3,3,3,3,3} (1 uno, 7 dos, 7 tres)
  2. {1,1,2,2,2,2,2,3,3,3,3,3,3,3,3} (2 unidades, 5 dos, 8 tres)
  3. {1,1,1,2,2,2,3,3,3,3,3,3,3,3,3} (3 unos, 3 dos, 9 tres)
  4. {1,1,1,1,2,3,3,3,3,3,3,3,3,3,3} (4 unidades, 1 dos, 10 tres)

Desafío

El desafío es escribir una función enumerateen el idioma de su elección que enumere todas las combinaciones como se describe anteriormente:

  1. La lista de denominaciones. Por ejemplo {1,5,10,25}. Puede usar listas o matrices.
  2. Un entero no negativo yque denota la suma de cada combinación.
  3. Un entero no negativo nque denota el número total de monedas.

El orden de los argumentos no importa. Se permiten funciones de punto libre.

La salida de la enumeratefunción debe ser una lista de combinaciones. Cada combinación debe ser única y debe ser una lista de nenteros que sumen y. Cada denominación debe aparecer al menos una vez en cada combinación y no debe faltar ninguna combinación. El orden de los enteros y las combinaciones no importa. Puede usar listas o matrices para la salida.

Tenga en cuenta los siguientes casos límite:

  1. Si ambos yy nson cero y la lista de denominaciones está vacía, la salida es una lista de una combinación, la combinación vacía (es decir {{}}).
  2. De lo contrario, si yes cero, nes cero o la lista de denominaciones está vacía, la salida es una lista de combinaciones cero (es decir {}).
  3. De manera más general, si yes menor que la suma de las denominaciones o nes menor que el número de denominaciones, entonces el resultado es una lista de combinaciones cero.

La puntuación se basará en el tamaño de todo el programa en bytes. Tenga en cuenta que esto incluye la enumeratefunción, funciones auxiliares, declaraciones de importación, etc. No incluye casos de prueba.

Aadit M Shah
fuente
Estoy bastante seguro de que he visto este desafío en alguna parte ...
Leaky Nun
Espero que esta pregunta no sea un duplicado. No pude encontrar la misma pregunta en Code Golf. Por lo tanto, lo publiqué.
Aadit M Shah
@PeterTaylor Si yes menor que la suma de las denominaciones, en algún momento de su solución recursiva alcanzará el caso base donde la lista de denominaciones está vacía. Por lo tanto, la respuesta será {}(es decir, no se encontró solución). Si nes menor que el número de denominaciones, eventualmente llegará al caso base donde n = 0pero y != 0. Por lo tanto, la respuesta será nuevamente {}.
Aadit M Shah
@PeterTaylor De hecho. Podría haber asumido demasiado sobre los detalles de implementación. ¿Sabrías cómo arreglar eso?
Aadit M Shah
10
Le sugiero que quite la bandera "Aceptada" hasta que obtenga una respuesta que funcione. Y en general, es sensato esperar un par de días antes de aceptar.
Peter Taylor

Respuestas:

2

05AB1E, 20 bytes

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

De entrada está en el orden: list of values, nr of coins, sum to reach.

Explicación en resumen

  1. Obtenga todas las permutaciones de la lista de monedas de longitud: final length - length of unique coin list
  2. Agregue la lista de monedas únicas a estas listas.
  3. Si la suma es igual a la suma buscada, guarde la lista
  4. Salida de todas las listas guardadas

Pruébalo en línea

El compilador en línea no puede manejar una gran cantidad de monedas.

Emigna
fuente
4

MATL , 22 bytes

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

El orden de entrada es: conjunto de denominaciones, número de monedas tomadas ( n), suma deseada ( y).

Cada combinación se muestra en una línea diferente. La salida vacía se muestra como una cadena vacía (por lo tanto, nada).

Pruébalo en línea!

El código se queda sin memoria en el compilador en línea para el ejemplo en el desafío, pero funciona sin conexión con una computadora estándar, razonablemente moderna:

>> 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

Explicación

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
fuente
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]

Una función anónima que toma la entrada de una tupla de denominaciones de la forma (x_1, x_2, x_3 ... , x_k), un valor objetivo y varias monedas mediante un argumento, y devuelve una lista de tuplas de la forma [(solution_1), (solution_2), (solution_3), ... (solution_k)].

Cómo funciona

ItertoolsLa combinations_with_replacementfunción de se utiliza para generar todas las l-len(d)combinaciones, con reemplazo, de las denominaciones. Al agregar da cada una de estas combinaciones, se garantiza que cada denominación aparece al menos una vez, y que la nueva combinación tiene longitud l. Si los elementos de una combinación suman t, la combinación se agrega a la lista de retorno como una tupla.

Pruébalo en Ideone


Un 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)

Una función anónima que toma la entrada de una tupla de denominaciones de la forma (x_1, x_2, x_3 ... , x_k), un valor objetivo y varias monedas mediante un argumento, y devuelve un conjunto de tuplas de la forma {(solution_1), (solution_2), (solution_3), ... (solution_k)}.

Cómo funciona (otra versión)

Esto utiliza la productfunción de itertoolspara generar todos los l-len(d)arreglos de las denominaciones. Al agregar da cada una de estas combinaciones, se garantiza que cada denominación aparece al menos una vez, y que la nueva combinación tiene longitud l. Si los elementos de una combinación suman t, la combinación se ordena, se convierte de una lista a una tupla y se agrega a las tuplas de retorno. Finalmente, llamar setelimina cualquier duplicado.

Pruébalo en Ideone (otra versión)

TheBikingViking
fuente
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
fuente