Ocho monedas para el rey justo


22

Esta es una "contraparte" de otro rompecabezas, Ocho monedas para el rey justo en Puzzling.SE.

Puedes leer el rompecabezas de arriba para el fondo. Los detalles sobre este rompecabezas son los siguientes.

Se crea un conjunto de 8 tipos de monedas de diferentes valores, el rey quiere que descubras el N máximo, de modo que cualquier cantidad de precio de 0 a N se pueda pagar con una combinación de no más de 8 monedas y sin cargos.

Por ejemplo, (tomado de la respuesta de Glorfindel). Si se da un conjunto de monedas de valores 1, 2, 5, 13, 34, 89, 233, 610, su programa debería generar 1596, porque cada número entre 0 y 1596 (inclusive) puede representarse por la suma de no más de 8 números de la lista dada (los números pueden repetirse), mientras que 1597 no puede representarse de esa manera.

De manera matemática, si la entrada es un conjunto S que consta de 8 enteros positivos, la salida deseada N satisface que para cualquier número n entre 0 y N, exista x1, x2, x3, ..., x8 de manera que

x1+x2+...+x8=nandx1,x2,...,x8{0}S

Su objetivo es escribir un programa, una función o un fragmento que tome 8 números como entrada y genere el N máximo como se describió anteriormente.

Reglas:

  • Se permiten E / S flexibles, por lo que su programa puede tomar la entrada en cualquier forma que sea más adecuada. Puede suponer que los números de entrada se ordenan de la manera que mejor se adapte a su programa.
    • Indíquelo en su respuesta si su programa depende del orden de entrada
  • La entrada es un conjunto de 8 enteros positivos diferentes (sin ceros). La salida es un entero no negativo.
    • En caso de que no haya 1 en el conjunto de entrada, su programa debería generar 0 porque cualquier número de 0 a 0 satisface el requisito.
    • En el caso de una entrada no válida (el conjunto contiene números cero, negativos o duplicados), su programa puede hacer cualquier cosa.
  • Las lagunas estándar están prohibidas.
  • Su programa debería ejecutarse dentro de unos minutos en una computadora moderna.

Casos de prueba (tomados principalmente de las respuestas bajo la pregunta vinculada sobre Puzzling):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

Este es un , por lo que gana el programa o fragmento más corto en cada idioma.


1
Bonito rompecabezas, pero personalmente creo que algunos casos de prueba más serían útiles para probar nuestras presentaciones.
Sr. Xcoder

¿No sería mejor hacer que el tamaño de entrada sea un parámetro? Los enfoques de fuerza bruta tendrán problemas con 8
Luis Mendo

1
@iBug Entonces, la regla habitual es algo así como "las presentaciones deben ejecutarse en un minuto en una computadora moderna". Es difuso, pero generalmente lo suficientemente bueno, porque la diferencia entre la fuerza bruta y los enfoques eficientes es muy grande
Luis Mendo

1
La fuerza bruta aún es posible con su límite de tiempo de "unos minutos". Una versión ligeramente modificada de mi respuesta ejecuta el último caso de prueba en 1m20s en mi computadora portátil de 7 años.
nimi

1
@Arnauld Aclarado
iBug

Respuestas:



9

Jalea , 12 bytes

œċⱮ8Ẏ§ṢQJƑƤS

Pruébalo en línea!

Toma un promedio de ~ 3.7 segundos para ejecutar todos los casos de prueba en TIO en mi teléfono, por lo que sorprendentemente es bastante rápido.

Explicación

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell, 56 50 bytes

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

Pruébalo en línea!

Un enfoque de fuerza bruta. Agregue 0a la lista de monedas y pruebe todas las combinaciones de 8 selecciones. Encuentra el primer número nque no es igual a la suma de cualquiera de las selecciones y devuelve n-1.

Toma alrededor de 5m30s para [1, 2, 5, 13, 34, 89, 233, 610]el hardware de mi laptop de 7 años.

Editar: -6 bytes gracias a @ Ørjan Johansen

Una versión aún más corta (-2 bytes, de nuevo gracias a @ Ørjan Johansen) es

Haskell, 48 bytes

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

pero usa mucha más memoria y se encuentra con una gran paginación en mi máquina y no termina "en unos minutos".


1
Puedes usar mapM(0:)$c<$c. (De hecho, mapM(:0:c)cdebería funcionar, pero se agota el tiempo de espera en TIO para el caso de prueba dado)
Ørjan Johansen

4

Jalea , 9 bytes

Żœċ8§ḟ’$Ṃ

Pruébalo en línea!

Cómo funciona

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃguarda un byte, pero no estoy seguro si 8,5 minutos cuentan como unos pocos .
Dennis


4

JavaScript (ES6),  100 88 80  76 bytes

Esta es esencialmente una búsqueda de fuerza bruta, pero mejorada con poda para acelerarla. El tiempo de ejecución promedio para los casos de prueba es cercano a 1 segundo en TIO.

Asume que la matriz de entrada está ordenada de mayor a menor.

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

Pruébalo en línea!

Comentado

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Pari / GP , 57 bytes

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

Pruébalo en línea!


¿Está usando la función de generación?
Don brillante

1
@donbright Sí.
alephalpha

1
eso es increíble ... una de las pocas respuestas que no obliga a la solución a la fuerza bruta. muchos idiomas probablemente no tienen características simbólicas polinómicas incorporadas. Pari GP es genial.
Don brillante

2

Python 2 , 125 115 111 bytes

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

Pruébalo en línea!

Espera una lista de enteros como entrada.

Explicación:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6, 65 63 41 bytes ( 39 37 caracteres)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

Pruébalo en línea!

Este es un bloque anónimo que pasa sus datos como una matriz. El (0,|@_)es una forma rápida de añadir una 0a @_, y a pesar de que ha hecho dos veces, es todavía un poco más corto que @_.push: 0;el que necesitaría entonces espacios después de la _. Este es un enfoque de fuerza bruta que se basa un poco en el hecho de que son 8 combinaciones. Después de la adición cruzada, se crea una lista anónima para valores secuenciales. Con los operadores matemáticos, las listas se evalúan según su longitud, por lo que el -1 obtiene un doble deber: tener en cuenta el 0 y coaccionar a Int.

Esto puede llevar su tiempo dulce, pero cambiando uno o ambos (0,|@_)a (0,|@_.unique)antes del primero forse puede acelerar considerablemente. Eso agrega +7 (tiempo de ejecución <60s) o +14 (tiempo de ejecución <10s) a la puntuación si siente que el primero es demasiado lento (hice esto para el código vinculado para evitar tiempos de espera después de 60 segundos).

Editar: JoKing en los comentarios lo mejoró (misma idea, suma cruzada, luego devuelve el último resultado consecutivo) a un sorprendente 39 caracteres (41 bytes):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

Pruébalo en línea!

La tabulación final no necesita un 0, ahorrando unos pocos bytes al solo tener que agregar 0 una vez. Los xx 3imita el bucle (todavía quesos en las monedas que son una potencia de 2). El firstsub devuelve el primer número en la lista infinita 0..*(también ^Infes posible, pero no ahorra espacio) que +1no es miembro de la lista cruzada agregada. Al igual que el mío, es lento, así que agregue +7 por un tiempo uniquedespués del primer igual si siente que es demasiado lento para las pautas.


1
48 bytes . Técnicamente, uniqueno es necesario, pero lo acelera mucho
Jo King

@JoKing bien, no sé por qué no pensé en usarlo xx. Sabía que tenía que haber una manera de hacer la tabulación final de una manera mucho más corta usando funciones establecidas, pero mi cerebro no funcionaba.
user0721090601

El xx 1debería serxx 3
Jo King

@JoKing arreglado. También me di cuenta de que se pueden guardar dos caracteres (pero no bytes) usando^∞
user0721090601

En realidad, se puede ahorrar algo de bytes con el (1...*∉@_)-1lugar de utilizar first, (que dan cuenta es el mismo método que utiliza aquí )
Jo Rey

1

JavaScript (Node.js) , 171 145 115 bytes

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

Pruébalo en línea! Puerto de la respuesta de @ Mark's Python 3. 108 bytes en Firefox 30-57:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))

1

Wolfram Language (Mathematica) , 46 bytes

0//.x_/;Min[Tr/@FrobeniusSolve[#,x+1]]<9:>x+1&

Pruébalo en línea!

Enfoque de fuerza bruta: comprueba los enteros contando hacia arriba hasta que alcanza un valor que no se puede pagar en 8 monedas. Muy, muy lento (se agota el tiempo de espera), pero estoy bastante seguro de que la condición es correcta.


0

Limpio , 161 bytes

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

Pruébalo en línea!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.