Teorema del número poligonal de Fermat

24

El teorema del número poligonal de Fermat establece que cada entero positivo se puede expresar como la suma de, como máximo, números gonales. Esto significa que cada entero positivo puede expresarse como la suma de hasta tres números de triángulo, cuatro números cuadrados, cinco números pentagonales, etc. Su tarea es tomar un entero positivo , y un entero , y generar el enteros gonales que suman .norte norteXs3sX

El entero -ésimo - gonal, donde y , se puede definir de dos maneras. La forma no matemáticas-y es que el º número -gonal puede ser construido como un polígono regular con lados, cada uno de longitud . Por ejemplo, para (números triangulares):nortesnorte1s3nortessnortes=3

triangulos

Ver aquí para ejemplos con una más grande .s

La definición matemática-y es mediante el uso de la fórmula para , que produce la -ésima número -gonal:PAGS(norte,s)nortes

P(n,s)=n2(s2)n(s4)2

que se da en la página de Wikipedia aquí .

Entrada

Dos números enteros positivos, y , con la condición de . Puede ingresar estos enteros en la representación más natural en su idioma (decimal, unario, números de iglesia, números de coma flotante con valor entero, etc.).sxs3

Salida

Una lista de los números enteros, , con una longitud máxima de , donde la suma de es igual a y todos los números enteros en son números enteros -gonal. Una vez más, los números enteros se pueden generar en la representación natural en su idioma, con cualquier separador distinto y consistente (de modo que los caracteres no decimales para la salida decimal, un carácter diferente del utilizado para la salida unaria, etc.)LsLxLs

Reglas

  • Las entradas o salidas nunca excederán el límite entero para su idioma
  • L no tiene que ser ordenado
  • En caso de múltiples salidas posibles, cualquiera o todas son aceptables
  • Este es el por lo que gana el código más corto en bytes

Casos de prueba

   x,  s => L
   1,  s => 1
   2,  s => 1, 1
   5,  6 => 1, 1, 1, 1, 1
  17,  3 => 1, 6, 10
  17,  4 => 1, 16
  17,  5 => 5, 12
  36,  3 => 36
  43,  6 => 15, 28
 879, 17 => 17, 48, 155, 231, 428
4856, 23 => 130, 448, 955, 1398, 1925
caird coinheringaahing
fuente
Sandbox post
caird coinheringaahing
¿Puede la salida tener algo de relleno cero? Por ejemplo, si consideramos x=17, s=5, ¿podríamos producir en 5,12,0,0,0lugar de solo 5,12?
falla
@flawr Mientras la longitud de la matriz no exceda , incluso con relleno, está biens
caird coinheringaahing
¿Se permiten repeticiones o debo agregar un Qa mi envío?
Jonathan Allan
@JonathanAllan Las salidas repetidas están perfectamente bien (si se obtienen múltiples soluciones)
caird coinheringaahing

Respuestas:

6

Haskell , 78 80 77 bytes

Calculamos el producto cartesiano de los primeros norte números s-gonales, y luego encontramos la primera entrada que suma norte .

s#n=[x|x<-mapM(map(\n->s*(n^2-n)`div`2+n*(2-n)))([0..n]<$[1..s]),sum x==n]!!0

Pruébalo en línea!

falla
fuente
6

JavaScript (ES6),  83  80 bytes

Una búsqueda recursiva rápida que maximiza el término más pequeño de la salida.

Toma entrada como (s)(x).

s=>g=(x,n=0,a=[],y=~n*(~-n-n*s/2))=>x<y?x|a[s]?0:a:g(x,n+1,a)||g(x-y,n,[...a,y])

Pruébalo en línea!

Fórmula

Resulta más corto usar una fórmula basada en 0 para calcular los números s gonales en JS, es decir, comenzar con norte=0 0 y calcular PAGS(norte+1,s) :

PAGS(norte+1,s)=((norte+1)2(s-2)-(norte+1)(s-4 4))/ /2=(norte2(s-2)+nortes+2)/ /2=-(norte+1)((norte-1)-nortes/ /2)

que se puede escribir en 14 bytes:

~n*(~-n-n*s/2)

Comentado

s =>                         // main function taking s
  g = (                      // recursive function g
    x,                       // taking x
    n = 0,                   // start with n = 0
    a = [],                  // a[] = list of s-gonal numbers
    y =                      // y = P(n + 1, s)
      ~n * (~-n - n * s / 2) //   = -(n + 1) * ((n - 1) - n * s / 2)
  ) =>                       //
    x < y ?                  // if x is less than P(n + 1, s):
      x | a[s] ?             //   if x is not equal to 0 or a[] is too long:
        0                    //     failed: return 0
      :                      //   else:
        a                    //     success: return a[]
    :                        // else:
                             //   process recursive calls:
      g(x, n + 1, a) ||      //   preferred: try to increment n
      g(x - y, n, [...a, y]) //   fallback : try to use the current s-gonal number
Arnauld
fuente
@AZTECCO Puedo intentar arreglarlo más tarde. Eliminado por ahora.
Arnauld
Gracias. ¡Esperándolo!
AZTECCO
4

Haskell , 55 bytes

n%s=[l|l<-mapM(\_->scanl(+)0[1,s-1..n])[1..s],sum l==n]

Pruébalo en línea!

Produce todas las soluciones posibles. Define los números s-gonales como la suma acumulativa de la progresión aritmética.

1, s-2, 2*s-3, 3*s-4, ...
xnor
fuente
3

Jalea , 17 bytes

x’2;’ÄÄx⁸ŒPS⁼¥Ƈ⁹Ḣ

Un enlace diádico (muy, muy ineficiente) que acepta sa la izquierda y xa la derecha, lo que produce la respuesta más corta posible como una lista de enteros (ordenados de forma ascendente).

Pruébalo en línea! ¡No tiene mucho sentido intentarlo con valores mucho más altos!

¿Cómo?

x’2;’ÄÄx⁸ŒPS⁼¥Ƈ⁹Ḣ - Link: s, x                    e.g.  5, 17
x                 - repeat (s) (x) times                [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
 ’                - decrement (vectorises)              [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
  2;              - prepend a two                       [2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4]
    ’             - decrement (vectorises)              [1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
     Ä            - cumulative sums                     [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49, 52]
      Ä           - cumulative sums                     [1, 5, 12, 22, 35, 51, 70, 92, 117, 145, 176, 210, 247, 287, 330, 376, 425, 477]
       x⁸         - repeat (each of those) (s) times    [1, 1, 1, 5, ..., 425, 477, 477, 477]
         ŒP       - power-set                           [[], [1], [1], ..., [1, 1], ..., [5, 22, 70], ... etc]
                      (this has 2^(x(s+1)) entries ...this example would have 2^(17(5+1)) = 2^102 = 5070602400912917605986812821504 entries!)
                      (Note: the lengths increase left to right)
              Ƈ   - filter keep if:
             ¥    -   last two links as a dyad:
           S      -     sum
            ⁼  ⁹  -     equals (x)?                     [[5,12], ... , [5,12], [1, 1, 5, 5, 5], ... , [1, 1, 5, 5, 5], [1, 1, 1, 1, 1, 12], ...]
                Ḣ - head                                [5,12]
Jonathan Allan
fuente
@AZTECCO Eso está perfectamente bien, se agota el tiempo de espera en TIO allí a los 60 segundos (estoy bastante seguro de que incluso un número de entrada mucho menor que ese tiempo de espera). Como señalo en mi respuesta, esto es "muy, muy ineficiente" y que "no tiene mucho sentido intentarlo con valores mucho más altos". Recuerde, el código dado para una solución de código de golf solo necesita trabajo con recursos infinitos.
Jonathan Allan
ok probé con s = 3 yn = 5 y me tomó 12 segundos !! Me gusta esta solución ineficiente y confiaré en ti, incluso si es casi imposible probarla :) ¡gracias!
AZTECCO
1
Xs
3

Ruby , 79 bytes

norte ss

norte2(s-2)-norte(s-4 4)2norte(nortes-2norte-s+4 4)2

->n,s{a=(0..n).map{|i|i*(i*s-2*i-s+4)/2};a.product(*[a]*~-s).find{|a|a.sum==n}}

Pruébalo en línea!

Tinta de valor
fuente
2

Retina , 111 bytes

\d+
*
~(`$
$"
0%["^_+ "|""]'$L$`\G_(?<=(?=___(_*))_+)
((_(?($.(2*$>`))$1\$.(2*$>`)))$*)
1%|' L$`\G_
$$.$.($`$>`

Pruébalo en línea! El enlace incluye casos de prueba. Toma entrada en el orden s n. Explicación:

\d+
*

Convierte a unario.

~(`

Después de procesar las etapas restantes, trátelas como un programa Retina y ejecútelas en la misma entrada.

$
$"

Duplicar la línea.

0%["^_+ "|""]'$L$`\G_(?<=(?=___(_*))_+)
((_(?($.(2*$>`))$1\$.(2*$>`)))$*)

Reemplace la primera copia con una expresión regular que omita el primer número y luego coincida s scon los números gonales. Los números mismos se capturan en grupos de captura impares y los grupos de captura pares se utilizan para garantizar que todos los números sean sgonales.

1%|' L$`\G_
$$.$.($`$>`

Reemplace la segunda copia con una lista separada por espacios de los grupos de captura impares.

Como ejemplo, el código generado para una entrada de 5 17es el siguiente:

^_+ ((_(?(2)__\2))*)((_(?(4)__\4))*)((_(?(6)__\6))*)((_(?(8)__\8))*)((_(?(10)__\10))*)$
$.1 $.3 $.5 $.7 $.9
Neil
fuente
1

APL (NARS), 149 caracteres, 298 bytes

r←f w;n;s;i;k
(n s)←w⋄r←⍬⋄→0×⍳s<3⋄i←1
→0×⍳n<k←2÷⍨(i×i×s-2)-i×s-4⋄r←r,k⋄i+←1⋄→2

h←{0=≢b←((v←↑⍵)=+/¨a)/a←{0=≢⍵:⊂⍬⋄m,(⊂1⌷⍵),¨m←∇1↓⍵}f⍵:v⍴1⋄k←↑⍋≢¨b⋄k⊃b}

si no encuentra soluciones "0 = ≢b" que el retorno para la entrada (ns), n veces 1; de lo contrario, devolvería la suma de números s que tiene menos suma ...

prueba:

  h 1 3
1 
  h 2 8
1 1 
  h 5 6
1 1 1 1 1 
  h 17 3
1 6 10 
  h 17 4
1 16 
  h 17 5
5 12 
  h 36 3
36 
  h 43 6
15 28 
  h 879 17
17 48 155 231 428 
  h 4856 23
321 448 596 955 2536 
  +/h 4856 23
4856

El problema de esto: no encuentra alguna solución, tiene algún número repetido en la suma ...

RosLuP
fuente
0

C ++ (clang) , 198 bytes

#import<vector>
using V=std::vector<int>;V f(int n,int s){V _{0};int z=1,a=0,b=1,i,t;for(;a<n;b+=s-2)_.push_back(a+=b),++z;V o;for(t=a=0;t-n;b=++a)for(o=V(s),t=i=0;b;b/=z)t+=o[i++]=_[b%z];return o;}

Pruébalo en línea!

V=vector<int> 
V _{0}; // initialized with one element =0 
int z=1, // vector size 
a=0,b=1,i,t;for(;a<n;b+=s-2)_.push_back(a+=b),++z;
// pushes polygons in V
V o; // vector to be returned 
for(t=a=0;t-n;b=++a) // ends when t=n
// loop to generate multi-dimension indexes
// for example a=1234 z=10
// a%z->4 , a/=z , a%z-> 3 , ... 2 , 1
for(o=V(s),t=i=0;b;b/=z)// loop to extract indexes
t+=o[i++]=_[b%z]; // put the sum in t and values in o
return o
AZTECCO
fuente