Cadena de adición más corta

23

Una cadena de suma es una secuencia de enteros que comienza con 1, donde cada entero que no sea el 1 inicial es una suma de dos enteros anteriores.

Por ejemplo, aquí hay una cadena de suma:

[1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Estas son las sumas que lo convierten en una cadena de suma:

1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
3 + 4 = 7
1 + 7 = 8
8 + 8 = 16
16 + 16 = 32
7 + 32 = 39
32 + 39 = 71

En este desafío, se le dará un número entero positivo n, y debe generar una de las cadenas de suma más cortas que termina en n.

Ejemplos: tenga en cuenta que hay muchas salidas posibles, todo lo que debe encontrar es una cadena de suma que sea igual de corta:

1: [1]
2: [1, 2]
3: [1, 2, 3]
4: [1, 2, 4]
5: [1, 2, 3, 5]
6: [1, 2, 3, 6]
7: [1, 2, 3, 4, 7]
11: [1, 2, 3, 4, 7, 11]
15: [1, 2, 3, 5, 10, 15]
19: [1, 2, 3, 4, 8, 11, 19]
29: [1, 2, 3, 4, 7, 11, 18, 29]
47: [1, 2, 3, 4, 7, 10, 20, 27, 47]
71: [1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Reglas de E / S estándar, etc. Prohibidas las lagunas estándar. Código de golf: gana pocos bytes.

isaacg
fuente
1
Relacionado
Peter Taylor
1
¿Se nos permite sacar la cadena en orden inverso?
Arnauld
@Arnauld No, este pedido específico.
isaacg

Respuestas:

6

Haskell , 57 bytes

c=[1]:[x++[a+b]|x<-c,a<-x,b<-x]
f n=[x|x<-c,last x==n]!!0

Una solución de fuerza bruta. Pruébalo en línea!

Explicación

La lista infinita ccontiene todas las cadenas de suma, ordenadas por longitud. Se define inductivamente en términos de sí mismo, tomando una lista xde cy dos elementos de x, y agregando su suma a x. La función fencuentra la primera lista cque termina con el número deseado.

c=            -- c is the list of lists
 [1]:         -- containing [1] and
 [x           -- each list x
  ++[a+b]     -- extended with a+b
 |x<-c,       -- where x is drawn from c,
  a<-x,       -- a is drawn from x and
  b<-x]       -- b is drawn from x.
f n=          -- f on input n is:
 [x           -- take list of those lists x
 |x<-c,       -- where x is drawn from c and
  last x==n]  -- x ends with n,
 !!0          -- return its first element.
Zgarb
fuente
4

Brachylog , 14 bytes

∧≜;1{j⊇Ċ+}ᵃ⁽?∋

Pruébalo en línea!

Una sumisión de fuerza bruta que construye todas las cadenas de suma posibles utilizando la profundización iterativa, deteniéndose cuando se encuentra una cadena que contiene su argumento correcto. A diferencia de la mayoría de las presentaciones de Brachylog, esta es una presentación de función que ingresa a través de su argumento derecho (convencionalmente llamado Salida) y las salidas a través de su argumento izquierdo (convencionalmente llamado Entrada); hacer esto es algo controvertido, pero la meta respuesta más votada sobre el tema dice que es legal (y hacerlo es consistente con nuestros valores predeterminados normales de E / S para las funciones). Si usáramos la entrada y la salida de una manera más convencional, serían 16 bytes (∧≜;1{j⊇Ċ+}ᵃ⁽.∋?∧), porque el lado derecho del programa no podría hacer uso de la restricción implícita (por lo tanto, necesitaría deshabilitarla y dar una nueva restricción explícita, a un costo de 2 bytes).

Explicación

∧≜;1{j⊇Ċ+}ᵃ⁽?∋
∧               Disable implicit constraint to read the left argument
 ≜;        ⁽    Evaluation order hint: minimize number of iterations
    {    }ᵃ     Repeatedly run the following:
   1      ᵃ       From {1 on the first iteration, results seen so far otherwise}
     j            Make {two} copies of each list element
      ⊇           Find a subset of the elements
       Ċ          which has size 2
        +         and which sums to {the new result for the next iteration}
             ∋    If the list of results seen so far contains {the right argument}
            ?     Output it via the left argument {then terminate}

Una sutileza interesante aquí es lo que sucede en la primera iteración, donde la entrada es un número en lugar de una lista como en las otras iteraciones; comenzamos con el número 1, hacemos dos copias de cada dígito (haciendo el número 11), luego encontramos una subsecuencia de 2 dígitos (también el número 11). Luego tomamos su suma de dígitos, que es 2, y como tal la secuencia comienza [1,2]como queremos. En iteraciones futuras, estamos empezando con una lista como [1,2], duplicando a [1,2,1,2], a continuación, tomar una subsecuencia de dos elementos ( [1,1], [1,2], [2,1], o [2,2]); claramente, las sumas de cada uno de estos serán los siguientes elementos válidos de la cadena de adición.

Es un poco frustrante aquí que la sugerencia de orden de evaluación se necesita aquí, especialmente el componente (parece que toma su sugerencia de orden de evaluación desde adentro en lugar de afuera por defecto, por lo tanto, el uso más bien crudo para forzar el problema).


fuente
Había intentado durante unos 30 minutos encontrar una forma corta de hacer este desafío. Mi solución fue mucho más larga que esto.
Fatalize
1
@Fatalize: es uno de esos componentes internos que rara vez aparece, pero cuando lo necesitas, realmente lo necesitas, ya que no hay una forma remotamente corta de implementarlo usando otras construcciones de control. Una vez que me di cuenta de que esto era un desafío, el resto vino directamente desde allí.
2

Jalea , 17 bytes

’ŒP;€µ+þ;1Fḟ@µÐḟḢ

Emite la primera solución lexicográfica en tiempo exponencial.

Pruébalo en línea!

Cómo funciona

’ŒP;€µ+þ;1Fḟ@µÐḟḢ  Main link. Argument: n (integer)

’                  Decrement; n-1.
 ŒP                Powerset; generate all subarrays of [1, ..., n-1], sorted first
                   by length, then lexicographically.
   ;€              Append n to all generate subarrays.
     µ       µÐḟ   Filterfalse; keep only subarrays for which the chain between the
                   two chain separators (µ) returns a falsy value.
     µ             Monadic chain. Argument: A (array of integers)
      +þ               Add table; compute the sums of all pairs of elements in x,
                       grouping the results by the right addend.
        ;1             Append 1 to the resulting 2D array.
          F            Flatten the result.
           ḟ@          Filterfalse swapped; remove all elements of A that appear in
                       the result. This yields an empty list for addition chains.
                Ḣ  Head; select the first result.
Dennis
fuente
2

JavaScript (ES6), 83 86 bytes

Editar: arreglado para generar la lista en orden no inverso

n=>(g=(s,a=[1])=>s-n?s>n||a.map(v=>g(v+=s,a.concat(v))):r=1/r|r[a.length]?a:r)(r=1)&&r

Manifestación

Arnauld
fuente
2

PHP, 195 bytes

function p($a){global$argn,$r;if(!$r||$a<$r)if(end($a)==$argn)$r=$a;else foreach($a as$x)foreach($a as$y)in_array($w=$x+$y,$a)||$w>$argn||$w<=max($a)?:p(array_merge($a,[$w]));}p([1]);print_r($r);

Pruébalo en línea!

Jörg Hülsermann
fuente
Desafortunadamente, este algoritmo no da respuestas óptimas, por ejemplo, para 15.
Neil
@Neil ahora es más largo pero funciona. No tengo idea en este momento de cómo decidir cuál de las dos formas es la correcta. Tal vez el recuento de números primos juega un papel
Jörg Hülsermann
Este código no pasa la prueba 149. La longitud debe ser 10, no 11
J42161217
@Jenny_mathy corregido
Jörg Hülsermann
1

Mathematica, 140 bytes

t={};s={1};(Do[While[Last@s!=#,s={1};While[Last@s<#,AppendTo[s,RandomChoice@s+Last@s]]];t~AppendTo~s;s={1},10^4];First@SortBy[t,Length@#&])&

.

produce una cadena de adición más corta diferente cada vez que la ejecuta

Pruébelo en línea,
pegue el código con Ctrl + V, coloque la entrada, es decir, [71] al final del código y presione Mayús + Entrar

J42161217
fuente
Como no tengo acceso a Mathematica, ¿qué longitud de cadena da esto para una entrada de 15?
Neil
la correcta {1, 2, 3, 5, 10, 15}
J42161217
3
Para la entrada 149, obtuve una cadena de longitud 11 de su programa, pero existe una de longitud 10 ( [1,2,4,5,9,18,36,72,77,149]). Parece que su programa usa muestreo aleatorio y no se garantiza que encuentre la solución óptima.
Zgarb
¡fijo! pero lleva más tiempo
J42161217
1

Pyth, 13 bytes

h-DsM^N2/#QyS

Banco de pruebas

Da la primera cadena más corta lexicográficamente. Es bastante lento, pero no está tan mal.19 completa en unos 30 segundos con pypy.

Algunas ideas de la solución de @ Dennis.

Realmente me gusta este, hay un montón de trucos interesantes involucrados.

Explicación:

h-DsM^N2/#QyS
h-DsM^N2/#QySQ    Implicit variable introduction
            SQ    Inclusive range, 1 to input.
           y      Subsets - all subsets of the input, sorted by length then lexicographically
                  Only sorted subsets will be generated.
                  Our addition chain will be one of these.
        /#Q       Filter for presence of the input.
  D               Order by
 -                What's left after we remove
     ^N2          All pairs of numbers in the input
   sM             Summed
h                 Output the list that got sorted to the front.

Esto todavía es un poco difícil de entender, pero déjame intentar explicarte con un poco más de detalle.

Comenzamos con ySQ, que da todos los posibles subconjuntos ordenados de[1, 2, ... Q] , en orden creciente de tamaño. La cadena de adición más corta es definitivamente una de estas, pero necesitamos encontrarla.

Lo primero que haremos es filtrar la lista para mantener solo las listas que contienen un Q. Hacemos esto con /#Q.

A continuación, ordenamos la lista por lo que queda después de eliminar el resultado de una determinada función. -Dórdenes por el resto después de eliminar algo.

Lo que eliminamos es sM^N2dónde Nestá la lista de la que eliminamos cosas. ^N2da el producto cartesiano de Nsí mismo, todos los pares posibles de dos elementos en N. sMluego suma cada uno de los pares.

¿Cuál es el resultado más pequeño posible, después de hacer esta eliminación? Bueno, el elemento más pequeño en la lista de entrada definitivamente permanecerá, porque todos los números son positivos, por lo que cualquier suma de dos números será mayor que el número más pequeño. Y habrá al menos un número, porque verificamos que la entrada estaba presente en la lista. Por lo tanto, el resultado más pequeño posible será cuando cada número, excepto el número más pequeño, sea la suma de otros dos números en la lista, y el número más pequeño en la lista sea 1. En este caso, la clave de clasificación será[1] . Estos requisitos significan que la lista debe ser una cadena de adición.

Entonces, clasificamos las cadenas de adición al frente. Recuerde que yda sus subconjuntos en orden creciente de tamaño, por lo que la lista que se ordena al frente debe ser una de las cadenas de adición más cortas. hselecciona esa lista.

isaacg
fuente