Calcola il coefficiente multinomiale


27

Tempo per un'altra sfida semplice a cui tutti possono partecipare!

Il teorema multinomiale afferma: Formula per calcolare l'ennesima potenza di un multinomiale

L'espressione tra parentesi è il coefficiente multinomiale, definito come:

Coefficiente multinomiale

Consentire ai termini k i di spaziare su tutte le partizioni intere di n fornisce l' n -esimo livello del m -simplex di Pascal . Il tuo compito è calcolare questo coefficiente.

Compito

Scrivi un programma o una funzione che accetta numeri m , n , k 1 , k 2 , ..., k m-1 e genera o restituisce il coefficiente multinomiale corrispondente. Il tuo programma può facoltativamente prendere m come argomento aggiuntivo, se necessario. Si noti che k m non è presente nell'input.

  • Questi numeri possono essere inseriti in qualsiasi formato uno preferisca, ad esempio raggruppati in elenchi o codificati in unario, o qualsiasi altra cosa, purché il calcolo effettivo del coefficiente multinomiale venga eseguito dal codice e non dal processo di codifica.

  • Il formato di output è altrettanto flessibile.

  • Tutto il codice dovrebbe essere eseguito in meno di un minuto per n e m fino a 1000.

  • Non preoccuparti dell'overflow di numeri interi.

  • Non sono ammessi incorporati progettati per calcolare il coefficiente multinomiale.

  • Si applicano scappatoie standard.

punteggio

Questo è il codice golf: vince la soluzione più breve in byte.

Casi test

Input: 3, [2, 0]
Output: 3

Input: 3, [1, 1]
Output: 6

Input: 11, [1, 4, 4]
Output: 34650

Input: 4, [1,2]
Output: 12

Input: 15, [5,4,3,2]
Output: 37837800

Input: 95, [65,4,4]
Output: 1934550571913396675776550070308250

Input: 32, [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]
Output: 4015057936610313875842560000000

Input: 15, [3,3,3,3]
Output: 168168000

Input: 1000, [10,10,10,10,10,10,10,10,10,10,100,100,100,100,100,100,100,100]
Output: 1892260836114766064839886173072628322819837473493540916521650371620708316292211493005889278395285403318471457333959691477413845818795311980925098433545057962732816261282589926581281484274178579110373517415585990780259179555579119249444675675971136703240347768185200859583936041679096016595989605569764359198616300820217344233610087468418992008471158382363562679752612394898708988062100932765563185864346460326847538659268068471585720069159997090290904151003744735224635733011050421493330583941651019570222984959183118891461330718594645532241449810403071583062752945668937388999711726969103987467123014208575736645381474142475995771446030088717454857668814925642941036383273459178373839445456712918381796599882439216894107889251444932486362309407245949950539480089149687317762667940531452670088934094510294534762190299611806466111882595667632800995865129329156425174586491525505695534290243513946995156554997365435062121633281021210807821617604582625046557789259061566742237246102255343862644466345335421894369143319723958653232683916869615649006682399919540931573841920000000000000

Input: 33, [17]
Output: 1166803110

Input: 55, [28]
Output: 3824345300380220

Possiamo avere errori di imprecisione? Cioè, invece di 1934550571913396675776550070308250, possiamo produrre 1.9345505719133966e+33?
Conor O'Brien,

@ CᴏɴᴏʀO'Bʀɪᴇɴ Se hai usato i float a 64 bit, non sarai in grado di rappresentare l'input [1000 {999 ones}], perché l'esponente è molto al di là di ciò che i float a 64 bit possono rappresentare. (I float a 128 bit probabilmente saranno sufficienti, ma suppongo che tu voglia utilizzare il tipo di numero nativo di JavaScript?)
Martin Ender

@ MartinBüttner Sì, questo è un presupposto corretto.
Conor O'Brien,

2
@quintopia "Tempo per un'altra facile sfida alla quale tutti possono partecipare!". Tutti tranne me! (Dal momento che non ho idea di cosa siano Pascals simplex e multinomiali D :) LOL.
Ashwin Gupta,

@AshwinGupta Non preoccuparti. Devi solo calcolare l'espressione nella seconda immagine e sei a posto! 👍
quintopia

Risposte:


21

Gelatina , 7 6 byte

;_/!:/

Guarda, no Unicode! Questo programma accetta un unico elenco come input, con n al suo primo indice.

Provalo online! oppure verifica tutti i casi di test contemporaneamente .

Come funziona

;_/!:/ Input: A (list)

 _/    Reduce A by subtraction. This subtracts all other elements from the first.
;      Concatenate A with the result to the right.
   !   Apply factorial to all numbers in the resulting list.
    :/ Reduce the result by division. This divides the first element by the others.

Questo è praticamente l'algoritmo che avevo in mente come il più semplice.
Quintopia,

9

CJam, 11 byte

l~_:-+:m!:/

Inserisci come un unico elenco con il nprimo:

[95 65 4 4]

Questo gestisce gli input fino a ne m1000 praticamente all'istante.

Provalo qui.

Spiegazione

l~  e# Read a line of input and evaluate it.
_   e# Duplicate.
:-  e# Fold subtraction over the list. A fold is essentially a foreach loop that starts
    e# from the second element. Hence, this subtracts all the k_i from n, giving k_m.
+   e# Append k_m to the list.
:m! e# Compute the factorial of each element in the list.
:/  e# Fold division over the list. Again, this divides n! by each of the k_i!.

Sembra che in realtà perderai la concorrenza del conteggio dei byte, ma devo dire che sono impressionato dalla folle insensatezza di CJam.
phord,

@phord Well CJam non è una corrispondenza per Jelly (o Pyth per quella materia). Ma sono rimasto piuttosto sorpreso da me stesso quanto è finito. La mia prima soluzione aveva 21 byte e, sebbene non sembrasse ottimale, non pensavo di riuscire a tagliarlo a metà.
Martin Ender,

4

MATL , 21 15 byte

Mettiamo a frutto la funzione log-gamma . Questo evita lo straripamento interno lavorando con logaritmi di fattoriali, non con fattoriali stessi.

1+ZgiO$Gs-h1+Zgs-ZeYo

Funziona con la versione corrente (9.2.2) del linguaggio / compilatore, che è precedente a questa sfida.

Gli input sono: prima un numero, quindi un vettore numerico. Il risultato è prodotto come a double, che limita il massimo output da qualche parte intorno 2^52.

Esempio

>> matl 1+ZgiO$Gs-h1+Zgs-ZeYo
> 15
> [5 4 3 2]
37837800

Spiegazione

1+       % implicit input (number). Add 1
Zg       % log-gamma function
i        % input (numeric vector).
0$G      % push both inputs
s-       % sum the second input (vector) and subtract from first
h1+      % append to vector. Add 1
Zg       % log-gamma function, element-wise on extended vector
s        % sum of results
-        % subtract from previous result of log-gamma
Ze       % exponential
Yo       % round. Implicit display

4
Provalo online! ora ha il supporto sperimentale MATL: matl.tryitonline.net/… I suggerimenti sono benvenuti.
Dennis,

1
@Dennis Hey! Che sorpresa!!! Come posso ringraziarvi ?? Ho un suggerimento: se mai verrai a Madrid ti devo una buona cena e qualche drink
Luis Mendo

Sono davvero grato. È fantastico averlo online. Come gestiremo le revisioni? Sto ancora aggiornando costantemente la lingua, sai ...
Luis Mendo

Per ora, sto aggiornando manualmente gli interpreti. Se fai un aggiornamento, eseguimi il ping in The Nineteenth Byte e lo tirerò al più presto. - Dovrò andare a Madrid nel prossimo futuro, quindi terrò a mente la tua offerta. ;)
Dennis

@Dennis Grande! In questo modo possiamo incontrarci di persona!
Luis Mendo,

4

PowerShell, 91 74 byte

Corteggiare! La mia centesima risposta su PPCG!

param($n,$k)(1..$n-join'*'|iex)/(($k|%{$n-=$_;1..$_})+(1..$n)-join'*'|iex)

Accidenti. Non vinceremo il codice più corto, questo è certo. Usa un paio di trucchi accurati con intervalli, però. E questo è probabilmente completo senza senso per chiunque non abbia familiarità con PowerShell.

Spiegazione

Per prima cosa prendiamo input param($n,$k)e ci aspettiamo $kdi essere un array, ad es .\compute-the-multinomial-coefficient.ps1 11 @(1,4,4).

Inizieremo con il numeratore (tutto a sinistra di /). Questo è semplicemente un intervallo 1..$nche è stato -joineditato insieme *e quindi valutato iexper calcolare il fattoriale (ad es.1*2*3*...*$n ).

Successivamente, abbiamo un ciclo su $k|%{...}e ogni iterazione si sottrae il valore di corrente $_da $n(che non ci preoccupiamo più) di formulare $k_min seguito. Inoltre, generiamo l'intervallo di 1..$k_iogni iterazione, che viene lasciato sulla pipeline. Questi oggetti della pipeline vengono concatenati con la matrice con la seconda espressione, intervallo 1..$n(che è $k_ma questo punto). Tutto ciò viene infine -joinredatto insieme *e valutato iex, in modo simile al numeratore (funziona perché x! * y! = 1*2*3*...*x * 1*2*3*...*y, quindi non ci interessa l'ordine individuale).

Alla fine, /succede, il numeratore è diviso per il denominatore e l'output.

Gestisce correttamente l'output per numeri più grandi, poiché non stiamo esplicitamente lanciando alcuna variabile come particolari tipi di dati, quindi PowerShell eseguirà il cast silenzioso come diversi tipi di dati al volo, se necessario. Per i numeri più grandi, output tramite notazione scientifica per preservare al meglio cifre significative man mano che i tipi di dati vengono rilanciati. Ad esempio, .\compute-the-multinomial-coefficient.ps1 55 @(28)verrà emesso 3.82434530038022E+15. Presumo che questo sia OK dato che "il formato di output è altrettanto flessibile" è specificato nei commenti della sfida e della quintopia "Se il risultato finale può rientrare nei tipi interi supportati nativamente, allora il risultato deve essere accurato. non ci sono restrizioni su ciò che può essere prodotto. "


In alternativa

A seconda delle decisioni di formattazione dell'output, quanto segue a 92 byte

param($n,$k)((1..$n-join'*'|iex)/(($k|%{$n-=$_;1..$_})+(1..$n)-join'*'|iex)).ToString('G17')

Che è lo stesso del precedente, utilizza solo l'uscita esplicita la formattazione con .ToString('G17')per ottenere il numero desiderato di cifre. Per 55 @(28)questo uscirà3824345300380220.5


Modifica1: salvati 17 byte eliminandoli $de semplicemente calcolandoli direttamente, eliminando il calcolo eseguendo $k_mla $k
stringa lungo mentre eseguiamo il ciclo Modifica2: aggiunta versione alternativa con formattazione esplicita


3

APL (Dyalog Extended) , 9 byte

×/2!/+\⍛,

Provalo online!

Utilizzando l'idea della mia risposta APL su un'altra sfida che coinvolge i multinomi .

Una funzione tacita il cui argomento di sinistra è l'elenco di k, e l'argomento di destra è n. I casi di test controllano se è d'accordo con la soluzione di Adam con argomenti a sinistra ea destra capovolti.

Come funziona

×/2!/+\⍛,
     +\     Cumulative sum of k's (up to m-1'th element)
       ⍛,   Append n (sum of k_1 to k_m)
  2!/       Binomial of consecutive pairs
×/          Product

(K1+K2++Km)!K1!K2!Km!=(K1+K2)!K1!K2!×(K1+K2++Km)!(K1+K2)!K3!Km!

=(K1+K2)!K1!K2!×(K1+K2+K3)!(K1+K2)!K3!×(K1+K2++Km)!(K1+K2+K3)!Km!

==(K1+K2K1)(K1+K2+K3K1+K2)(K1++KmK1++Km-1)


2

Mathematica, 26 byte

#!/Times@@({#-+##2,##2}!)&

Esempio:

In[1]:= #!/Times@@({#-+##2,##2}!)&[95,65,4,4]

Out[1]= 1934550571913396675776550070308250

2

Python 3, 93 91

Grazie a Dennis e FryAmTheEggman .

f=lambda x:0**x or x*f(x-1)
def g(n,k):
    r=f(n)
    for i in k:r//=f(i)
    return r//f(n-sum(k))

ncome intero, kcome ripetibile.

Ungolfed:

import functools #cache

@functools.lru_cache(maxsize=None) #cache results to speed up calculations
def factorial(x):
    if x <= 1: return 1
    else: return x * factorial(x-1)

def multinomial(n, k):
    ret = factorial(n)
    for i in k: ret //= factorial(i)
    km = n - sum(k)
    return ret//factorial(km)

1
Puoi usare un singolo spazio invece di quattro per il bit dinamico degli spazi bianchi
Conor O'Brien

Ho usato le schede, sono state sostituite in questo post. Il conteggio dei byte sembra essere OK. Non sono sicuro del risultato float e del possibile overflow.
Trang Oul,

2
1. Questo produce un errore per 95, [65, 4, 4]. Si noti che l'input non contiene k_m . 2. Sembra che tu non stia usando from functools import*affatto.
Dennis,

2
1. Il tuo codice golf non viene utilizzato reduce. 2. import math;f=math.factorialsalva un byte. 3. Python 2 ti permetterebbe di sbarazzarti del secondo /in //.
Dennis,

1
Definizione fsul proprio consente di risparmiare alcuni byte : f=lambda x:0**x or x*f(x-1).
FryAmTheEggman,

2

APL (Dyalog Unicode) , 16 byte SBCS

Interamente basato sull'abilità matematica del mio collega Marshall .

Funzione infix anonima. Prende k come argomento destro e n come argomento sinistro.

{×/⍵!⍺-+10,⍵}

Provalo online!

{... } lambda anonimo; è argomento di sinistra ( n ) ed è argomento di destra ( k )

0,⍵ anteporre uno zero a k

¯1↓ elimina l'ultimo elemento da quello

+\ somma cumulativa di quello

⍺- sottrarre quello da n

⍵! ( k ) quello

×/ prodotto di quello


1

PARI / GP, 43 byte

Abbastanza diretto; a parte la formattazione, la versione non modificata potrebbe essere identica.

m(n,v)=n!/prod(i=1,#v,v[i]!)/(n-vecsum(v))!

1

Matlab 48 byte

È necessario impostare formata longin anticipo per ottenere la maggiore precisione. Quindi, è abbastanza semplice:

@(n,k)factorial(n)/prod(factorial([k,n-sum(k)]))

ans(95, [65,4,4])
ans =

 1.934550571913395e+33

1

Pyth, 10 byte

/F.!MaQ-FQ

Provalo online: dimostrazione

Spiegazione:

/F.!MaQ-FQ   implicit: Q = input list
       -FQ   reduce Q by subtraction
     aQ      append the result to Q
  .!M        compute the factorial for each number
/F           reduce by division

1

J, 16 byte

[(%*/)&:!],(-+/)

uso

Per valori più grandi, un suffisso di xviene utilizzato per indicare numeri interi di precisione estesi.

   f =: [(%*/)&:!],(-+/)
   11 f 1 4 4
34650
   15x f 5 4 3 2
37837800

Spiegazione

[(%*/)&:!],(-+/)  Input: n on LHS, A on RHS
             +/   Reduce A using addition
            -     Subtract that sum from n, this is the missing term
         ]        Get A
          ,       Append the missing term to A to make A'
[                 Get n
      &:!         Take the factorial of n and each value in A'
   */             Reduce using multiplication the factorials of A'
  %               Divide n! by that product and return

1

05AB1E , 8 byte

Ƹ«!R.«÷

Provalo online! Spiegazione:

Æ           Subtract all the elements from the first
 ¸«         Append to the original list
   !        Take the factorial of all the elements
    R.«÷    Reduce by integer division

Non riesco a trovare modi migliori per eseguire il passaggio 2 o il passaggio 4.




0

Clojure, 70 byte

#(let[a apply](a /(map(fn[x](a *(map inc(range x))))(conj %(a - %)))))

Crea una funzione anonima prendendo tutti gli argomenti come un unico elenco, con n prima.

30 caratteri vengono "sprecati" solo per definire la dannata funzione fattoriale. Oh bene.


0

Perl 6 ,  52  50 byte

->\n,\k{[*](1..n)div[*] ([*] 1..$_ for |k,[-] n,|k)}

Provalo

->\n,\k{[*](1..n)/[*] ([*] 1..$_ for |k,[-] n,|k)}

Provalo (il risultato è una Razionale con denominatore di 1)

Allargato:

->     # pointy block lambda
  \n,
  \k
{
    [*]( 1 .. n )   # factorial of 「n」

  /                 # divide (produces Rational)

    [*]             # reduce the following using &infix:«*»

      (
          [*] 1..$_ # the factorial of

        for         # each of the following

          |k,       # the values of 「k」 (slipped into list)
          [-] n,|k  # 「n」 minus the values in 「k」
      )
}
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.