Teorema dei numeri poligonali di Fermat


24

Il teorema dei numeri poligonali di Fermat afferma che ogni numero intero positivo può essere espresso come la somma di al massimo n numeri n poligonali. Ciò significa che ogni intero positivo può essere espresso come la somma di fino a tre numeri triangolo, quattro numeri quadrati, cinque numeri pentagonali ecc vostro compito è quello di prendere un intero positivo X , e un numero intero S3 , e per emettere i S interi -gonali che si sommano a X .

Il numero intero n - S -gonale, dove n1 e S3 , può essere definito in un paio di modi. Il modo non-matematica-y è che il n ° S numero -gonal può essere costruito come un poligono regolare con S lati, ciascuno di lunghezza n . Ad esempio, per S=3 (numeri triangolari):

triangoli

Vedi qui per esempi con una S più grande .

La definizione matematica è usando la formula per P(n,S) , che produce l' n - esimo numero S -gonale:

P(n,S)=n2(S-2)-n(S-4)2

che è riportato nella pagina di Wikipedia qui .

Ingresso

Due interi positivi, S e X , con la condizione S3 . Puoi inserire questi numeri interi nella rappresentazione più naturale nella tua lingua (decimali, unari, numeri di Church, numeri in virgola mobile con valori interi, ecc.).

Produzione

Un elenco di numeri interi, L , con una lunghezza massima di S , in cui la somma di L è uguale a X tutti i numeri interi in L sono numeri interi S -gonali. Ancora una volta, gli interi possono essere emessi nella rappresentazione naturale nella tua lingua, con qualsiasi separatore distinto e coerente (quindi caratteri non decimali per output decimale, un carattere diverso da quello usato per output unario ecc.)

Regole

  • Gli ingressi o le uscite non supereranno mai il limite intero per la tua lingua
  • L non deve essere ordinato
  • In caso di più uscite possibili, tutte o tutte sono accettabili
  • Questo è quindi vince il codice più breve in byte

Casi test

   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


L'output può avere un'imbottitura zero? Ad esempio, se consideriamo x=17, s=5che potremmo produrre 5,12,0,0,0invece di solo 5,12?
flawr

@flawr Finché la lunghezza dell'array non supera , anche con il padding, va beneS
caird coinheringaahing

Sono consentite le ripetizioni o devo aggiungere a Qalla mia richiesta?
Jonathan Allan il

@JonathanAllan Le uscite ripetute vanno benissimo (se si producono più soluzioni)
caird coinheringaahing

Risposte:


6

Haskell , 78 80 77 byte

Calcoliamo il prodotto cartesiano dei primi numeri n s-gonal e quindi troviamo la prima voce che somma a n .

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

Provalo online!


6

JavaScript (ES6),  83  80 byte

Una rapida ricerca ricorsiva che massimizza il termine più piccolo dell'output.

Accetta input come (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])

Provalo online!

Formula

Risulta più breve usare una formula basata su 0 per calcolare S numeri s -gonali in JS, cioè iniziare con n=0 e calcolare P(n+1,S) :

P(n+1,S)=((n+1)2(S-2)-(n+1)(S-4))/2=(n2(S-2)+nS+2)/2=-(n+1)((n-1)-nS/2)

che può essere scritto in 14 byte:

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

Commentate

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

@AZTECCO Potrei provare a risolverlo più tardi. Rimosso per ora.
Arnauld,

Grazie. Aspettandolo!
AZTECCO,


4

Haskell , 55 byte

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

Provalo online!

Produce tutte le possibili soluzioni. Definisce i numeri s-gonali come somma cumulativa della progressione aritmetica

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

3

Gelatina , 17 byte

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

Un collegamento diadico (molto molto inefficiente) che accetta sa sinistra ea xdestra che fornisce la risposta più breve possibile come un elenco di numeri interi (ordinati in ordine crescente).

Provalo online! - non serve molto provarlo per valori molto più alti!

Come?

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]

@AZTECCO Va benissimo, va in timeout su TIO a 60 secondi (sono abbastanza sicuro che anche un numero di input molto più piccolo di quello andrà in timeout). Come faccio notare nella mia risposta, questo è "molto molto inefficiente" e che "non ha molto senso provarlo per valori molto più alti!". Ricorda, il codice fornito per una soluzione di code-golf ha bisogno solo di lavoro, con infinite risorse.
Jonathan Allan,

ok ho provato con s = 3 e n = 5 e ci sono voluti 12 secondi !! Mi piace questa soluzione inefficiente e mi fiderò di te, anche se è quasi impossibile testarlo :) grazie!
AZTECCO,

1
XS

3

Rubino , 79 byte

n SS

n2(S-2)-n(S-4)2n(nS-2n-S+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}}

Provalo online!



2

Retina , 111 byte

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

Provalo online! Il link include casi di test. Accetta input nell'ordine s n. Spiegazione:

\d+
*

Converti in unario.

~(`

Dopo aver elaborato le fasi rimanenti, trattarle come un programma Retina ed eseguirle sullo stesso input.

$
$"

Duplica la linea.

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

Sostituisci la prima copia con un'espressione regolare che salta sopra il primo numero e quindi abbina i s snumeri -gonali. I numeri stessi vengono acquisiti in gruppi di acquisizione dispari e i gruppi di acquisizione pari vengono utilizzati per garantire che tutti i numeri siano s-gonali.

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

Sostituisci la seconda copia con un elenco separato da spazi dei gruppi di acquisizione dispari.

Ad esempio, il codice generato per un input di 5 17è il seguente:

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

1

APL (NARS), 149 caratteri, 298 byte

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}

in caso contrario, trovare le soluzioni "0 = ≢b" rispetto a return per (ns) input, n volte 1; altrimenti restituirebbe la somma dei numeri s che ha meno addend ...

test:

  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

Il problema di questo: non trova alcuna soluzione ha qualche ripetizione numerica nella somma ...


0

C ++ (clang) , 198 byte

#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;}

Provalo online!

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.