Elencare tutte le partizioni moltiplicative di n


28

Dato un numero positivo n , genera tutte le partizioni moltiplicative distinte di n in qualsiasi formato conveniente.

Una partizione moltiplicativa di n è un insieme di numeri interi, tutti maggiori di uno, in modo tale che il loro prodotto sia n . Ad esempio, 20 ha le seguenti partizioni moltiplicative distinte:

2 * 2 * 5
2 * 10
4 * 5
20

L'ordine non ha importanza, quindi 2 * 2 * 5è la stessa partizione di 2 * 5 * 2.


Esempi:

1 -> {}
2 -> {2}
4 -> {2, 2}, {4}
20 -> {2, 2, 5}, {2, 10}, {4, 5}, {20}
84 -> {2, 2, 3, 7}, {2, 2, 21}, {2, 14, 3}, {2, 6, 7}, {2, 42}, {4, 3, 7}, {28, 3}, {4, 21}, {6, 14}, {12, 7}, {84}


Risposte:


6

Brachylog , 16 byte

>~l:{1<}a.*?,.=o

Questa è una funzione (non un programma completo) che accetta un numero positivo come input e ne genera tutte le partizioni moltiplicative. (Ho anche evitato di usare qualsiasi builtin di fattorizzazione primaria in questa soluzione, principalmente perché non ero sicuro che avrebbero aiutato; potrei provare anche una soluzione più pesante incorporata a un certo punto.)

Provalo online! (È stato aggiunto un codice extra attorno alla funzione qui per trasformarlo in un programma completo; se fornisci direttamente la funzione mostrata sopra a TIO, eseguirà la funzione ma non stampa il suo output ovunque, il che è un po 'inutile come dimostrazione .)

Questo programma mi delude davvero, perché gran parte sta lavorando su bug nell'interprete Brachylog e su carenze nelle sue specifiche, piuttosto che risolvere effettivamente il problema; ma l'interprete è quello che è. (Anche con un programma come questo, l'interprete usa molta più memoria di quanto dovrebbe logicamente e si blocca a causa dell'esaurimento della memoria, ma fortunatamente su piccoli problemi riesce a produrre prima l'output desiderato.) In un'ipotetica "versione perfetta di Brachylog" potresti semplicemente scrivere ~*.o.:{>1}a,, che sarebbe più corto di 4 byte, ma avevo bisogno di aggiungere ulteriori vincoli per aiutare un po 'l'interprete. (Non mi piace molto Brachylog, e preferirei attenermi a Prolog, ma aveva bisogno di suggerimenti simili per far funzionare il programma e sono molto più lunghi da scrivere. Quindi Brachylog lo è.)

Spiegazione:

Come al solito, un programma Brachylog è un insieme di vincoli; per impostazione predefinita, il primo vincolo limita l'input rispetto a uno sconosciuto (che chiamerò A ), il secondo vincolo vincola A contro un secondo sconosciuto B e così via fino a raggiungere l'output. Alcuni caratteri, come ad esempio {}, possono cambiare questo flusso generale, quindi uso un diverso insieme di lettere (ad es. X / Y ) per rappresentare incognite nei predicati nidificati.

>       A is smaller than the input
~l      B has length A
  1<    X is 1, Y is larger
:{1<}a  For each element X of B, it corresponds to an element Y of C
.       C, the output, and D are all identical
*       E is the product of D's elements
?       E, the input, and F are all identical
,       There's no constraint between F and G
.       G, the output, and H are all identical
=       H and I are identical, and need to be evaluated early
o       The output can be produced by sorting I

Non è ancora chiaro come funzioni il programma, quindi proviamo a semplificare un po 'i vincoli. C , D , G , H e I sono tutti uguali (e uguali all'output). E e F sono uguali (e uguali all'ingresso). Quindi i nostri vincoli si riducono a questo:

  • A è la lunghezza di B e dell'uscita ed è più piccola dell'ingresso.
  • B è composto da tutti 1 e non è particolarmente utile (fa parte del programma semplicemente perché nell'interprete Brachylog esistente, ha :{1<}abisogno dell'argomento sinistro per avere una lunghezza limitata, altrimenti l'interprete va in un ciclo infinito).
  • L'output è costituito interamente da numeri maggiori di 1 (ovvero maggiori dell'elemento corrispondente di B ).
  • Il prodotto degli elementi dell'output è uguale all'input.
  • L'output è invariato ordinandolo (ovvero è in ordine).

Per inciso, non ho specificato esplicitamente che tutti gli elementi dell'output sono numeri interi, qualcosa che potrebbe sembrare necessario; tuttavia, il risolutore di vincoli di Brachylog non può gestire numeri non interi, quindi produrrà convenientemente solo le soluzioni che coinvolgono numeri interi.

Chiaramente, "la lunghezza dell'output è più piccola dell'ingresso" sarà vera ogni volta che l'output è una partizione moltiplicativa dell'ingresso (perché 2 x > x per tutte le x non negative , ovvero 2 x positive ). Quindi possiamo ignorare quel vincolo; è lì solo per dare all'interprete Brachylog una strategia di lavoro per la valutazione del programma. Gli altri vincoli (che l'output è ordinato, che il suo prodotto è l'input e che i suoi elementi sono tutti maggiori di 1) sono la definizione di una partizione moltiplicativa, e quindi questa funzione è fondamentalmente solo un'implementazione diretta della domanda.


6

Brachylog 1, 14 byte

:{$pp~c:*ao}fd

Provalo online!

Brachylog 2, 11 10 byte, sfida postdati lingua

{ḋp~c×ᵐo}ᵘ

Provalo online!

Maltysen ha risposto a questa domanda in 17 byte di Pyth, quindi ho trovato una soluzione Brachylog a 16 byte che ha funzionato traducendo le specifiche della domanda in Brachylog. Mentre lo facevo, Dennis scrisse una soluzione Jelly a 15 byte. Quindi ho dovuto scendere a 14 byte. Questa è una funzione che accetta l'input come argomento e restituisce un elenco di tutte le partizioni (anziché un generatore, come con la mia altra soluzione).

Qualche tempo dopo aver scritto questa risposta, Dennis e io siamo riusciti a ottenere la soluzione Jelly in modo cooperativo fino a 11 byte. Si scopre che esiste una nuova versione di Brachylog, con una sintassi più terser; postdatizza la sfida, quindi in realtà non conta, ma potrebbe gestire il totale di 11 byte in modo eccessivo non appena viene rilasciato; le revisioni successive del linguaggio (ispirate ad altre sfide) possono scendere a 10, come visto qui. I due programmi sono identici, con l'unica differenza è la sintassi.

A differenza della mia altra soluzione, che non ha fatto molto uso dei "primitivi del golf", ma piuttosto ha dichiarato il problema direttamente, questo ignora praticamente tutto il potere dei vincoli di Brachylog e fa invece la sua migliore impressione di Jelly, scrivendo una catena di vincoli per i quali l'argomento di sinistra è già noto (e quindi i vincoli agiscono semplicemente come monadi Jelly piuttosto che vincoli completi). Utilizza quindi lo stesso algoritmo della soluzione Pyth di @ Maltysen, che è probabilmente il modo più semplice per risolverlo usando le primitive tipiche del golf. (È interessante notare che la soluzione "basta affermare il problema" nella mia altra risposta sarebbe più breve se non per bug / carenze nell'interprete di Brachylog, nonostante la sua mancanza di utilizzo di primitivi del golf. Un giorno ho bisogno di scrivere un "miglioramento di Brachylog" al fine di ottenere una buona soluzione per questo tipo di problema; come vanno le lingue del golf, Brachylog è in realtà molto dettagliato.)

Il programma è composto da un generatore e un involucro attorno ad esso. Innanzitutto, ecco una spiegazione del generatore:

$pp~c:*ao  ḋp~c×ᵐo
$p         ḋ        Prime factor decomposition of the input
  p         p       Generate all permutations
   ~c        ~c     Generate all inverse concatenations (i.e. partitions)
     :*a       ×ᵐ   Take the product of each list element in each partition
        o        o  Sort each partition

Questo quasi risolve il problema, ma finiamo per generare molte delle partizioni molte volte ciascuna. Quindi abbiamo bisogno di un wrapper per deduplicare le soluzioni:

:{…}fd
:{…}f     Convert generator to list
     d    Remove duplicate elements

{…}ᵘ      Convert generator to list of unique elements

Perché non modificare la tua risposta eccezionale?
Downgoat,

3
@Downgoat: le due risposte usano approcci completamente diversi; gli algoritmi sono diversi, le funzionalità del linguaggio utilizzate sono per lo più indipendenti e simili. Non avrebbe senso sostituire quello più vecchio con quello più recente (e avrei potuto postare quello nuovo anche se fosse più lungo). Questo meta post suggerisce che è preferibile pubblicare risposte separate in questo tipo di situazione.

1
Non so se lo sai, ma puoi recuperare l'output impostando l'argomento su TIO su una variabile (cioè una lettera maiuscola). Per esempio .
Fatalizza il

5

Mathematica, 61 byte

±1={{}}
±n_:=Union@@(Sort/@Append[n/#]/@±#&/@Most@Divisors@n)

Definisce un operatore unario (ricorsivo) ±che restituisce l'elenco delle partizioni.


La matematica non richiede il punto e virgola alla fine?
Pavel,

@Pavel no, il punto e virgola elimina solo l'output nel blocco appunti interattivo. Grazie per averlo sottolineato, a proposito, ho lasciato per caso un punto e virgola alla fine.
Martin Ender,

4

Pyth - 17 byte

Accetta tutte le permutazioni della scomposizione in fattori primi, quindi partiziona ognuna e quindi produce tutte le partizioni, quindi mantiene solo le partizioni distinte.

{mS-*Md1s./M.p+1P

Test Suite .


4

Python 2, 70 byte

f=lambda n,k=2,l=[]:n/k and(n%k<1)*f(n/k,k,l+[k])+f(n,k+1,l)or 1/n*[l]

Emette un elenco di elenchi ordinati. Ad esempio f(20)è [[2, 2, 5], [2, 10], [4, 5], [20]].


Poiché il tipo intero incorporato di Python non ha limiti, il virgola mobile non è una soluzione accettabile poiché le imprecisioni interrompono la risposta per input troppo grandi.
orlp,

@orlp Ok, allora torna a Python 2.
xnor

TL; DR Penso che 998 non sia un input troppo grande ;-) IMO un codice davvero interessante, più simile alla latenza O(n)e rispetto al concorrente di Python 2 potrebbe essere più O(n^4)stile - mentre f (998) potrebbe far saltare memoria o l'hardware potrebbe morire durante l'esecuzione tempo di circa 80 giorni con l'altro algoritmo, questo qui converge dopo ca. 7 milli secondi sulla mia macchina per ottenere il risultato [[2, 499], [998]]. IMO il problema potrebbe essere più che per N > 998le RecursionError: maximum recursion depth exceeded in comparisonfermate del codice Python 3 sopra ... buon golf :-)
Dilettant

@Dilettant Non sono sicuro che O(n^4)sia abbastanza per la mia presentazione Python2: D Considerando il caso di test 998, il mio codice verrà eseguito 9 volte e calcolerà (n+r-1)! / r! / (n-1)!ogni volta la quantità di tuple, dove rcresce linearmente da 2, e n è 9 - 2. Ma ehi, almeno non devi modificare il limite di ricorsione ...
Yytsi,

@TuukkaX Avvertenza: non ho analizzato il codice, ho semplicemente sfogliato e confrontato lo sviluppo dei tempi di esecuzione tra i due candidati per alcuni N fino a 41, quindi ho pensato di impegnare il commento ;-) pile e ricorsione spesso carne facile, ma poi chiedi quanto siano profonde le domande di tipo in situazioni spiacevoli ... spero di averlo coniato abbastanza sfocato per la quantità di ricerche che sono state
condotte

3

Gelatina , 14 13 11 byte

Ḋx³ŒPQP=¥Ðf

Provalo online!

Ero abbastanza sicuro che la soluzione Jelly di Dennis potesse essere migliorata. Sfortunatamente, non sono riuscito a battere il record di Brachylog, ma sono riuscito a legarlo. Aggiornamento : con l'aiuto di @Dennis, ora è migliorato; Immagino che Jelly riprenda la corona.

Questo programma è incredibilmente inefficiente, con prestazioni O (2 n 2 ) (motivo per cui il test case sopra lo mostra per l'ingresso 4). Si completa rapidamente su 4, molto lentamente su 5 e potrebbe non essere praticamente possibile eseguire numeri più grandi.

È interessante notare che Brachylog è stato migliorato passando da una soluzione che descriveva il problema (di cui Brachylog è bravo) a una soluzione che utilizzava un algoritmo basato sulla fattorizzazione dell'input (di cui Jelly è brava); nel frattempo, la soluzione Jelly è stata migliorata allontanandosi dai suoi punti di forza e tornando a una soluzione che descrive semplicemente il problema.

Spiegazione:

Ḋx³ŒPQP=¥Ðf
Ḋ              List of integers from 2 to the input (apparently undocumented)
 x³            Make a number of copies of each that's equal to the input
   ŒP          Take all (possibly noncontiguous) subsequences of that list (!)
     Q         Remove duplicates
         Ðf    Filter, keeping elements where:
      P=         their product is equal to {the original input, by default}
        ¥      Parse preceding two links as a unit

Poiché l'output di Ḋxè ordinato, anche ogni sottosequenza deve essere ordinata e quindi non è necessario ordinarli singolarmente. Quindi "lo stesso output in ordini diversi è un duplicato" del problema, e "tutti i valori nell'output sono> 1" parte del problema, vengono risolti dalla generazione. A parte questo, quello che stiamo sostanzialmente facendo qui è "trova tutti gli elenchi per i quali P=³", cosa che facciamo (in modo incredibilmente inefficiente) generando tutti gli elenchi in questione e quindi filtrando quelli errati.

(Chiaramente, qualcuno deve inventare un ibrido di Jelly e Brachylog, oltre a un ottimo risolutore di vincoli, in modo da poter scrivere qualcosa sulla falsariga di {P=³}~un codice di deduplicazione e risolvere il programma in una lunghezza molto più breve. Potrebbe essere a una certa distanza, però.)


Per favore, qualcuno trova un personaggio di risparmio qui. Mi piacerebbe una "guerra dei byte" in cui le voci continuano ad accorciarsi di un byte ogni volta. Qui ci sono abbastanza byte sprecati in parti strutturali del programma che sembra che questo possa essere migliorabile.

1
Stavo per pubblicare qualcosa di sorprendentemente simile. (Dovrebbe rinfrescarsi più spesso.) 2rPuò diventare e P=³$$può diventare P=¥.
Dennis,

P=¥non funziona quando lo provo nell'interprete, anche se non sono del tutto sicuro del perché (logicamente, dovrebbe funzionare, ed è stata una delle cose che ho provato mentre scrivevo il post; l'ho provato di nuovo per assicurarmi, sicuramente non fa quello che mi aspettavo). fa, però, quindi immagino che ci sia il nostro salvataggio di un byte :-)

1
Non ho prestato attenzione a un altro dettaglio. Dovresti sostituirlo anche µcon ¹, poiché µrende l'intervallo ripetuto il nuovo argomento di sinistra.
Dennis,

Oh, certo. Quindi ora siamo scesi a 11, con molti meno personaggi, il che mi sta facendo sentire molto meglio. (Ho usato ³piuttosto che ¹solo per la varietà.)

2

JavaScript (ES6), 74 67 byte

f=(n,m=2,a=[])=>n>1?m>n?[]:f(n,m+1,a).concat(f(n/m,m,[...a,m])):[a]

for (var i = 1; i < 31; i++) console.log(JSON.stringify(f(i)));

Risolve il problema direttamente ricorsivo: per ogni intero m dal 2 al n , prendiamo ogni partizione di n / m con un elemento minimo di m (per evitare partizioni duplicati) e accodamento m . (Per ogni m che non divide n , questo dà l'array vuoto, poiché nessuna disposizione di numeri interi si moltiplica in un decimale.) Definiamo un caso base dell'array vuoto per 1 in modo da evitare la ricorsione infinita.


1

Python2, 198 191 172 180 byte

from itertools import*
n=input()
for i in range(2,len(bin(n))):
 for P in combinations_with_replacement(range(2,n),i):
  if reduce(lambda a,b:a*b,P)==n:print(P)
print[(n,),()][n<2]

Un programma completo. Questo potrebbe essere migliorato molto, quindi i suggerimenti sono benvenuti!

Uscite nell'intervallo da 1 a 31 (incluso):

(1,)
(2,)
(3,)
(2, 2), (4,)
(5,)
(2, 3), (6,)
(7,)
(2, 4), (2, 2, 2), (8,)
(3, 3), (9,)
(2, 5), (10,)
(11,)
(2, 6), (3, 4), (2, 2, 3), (12,)
(13,)
(2, 7), (14,)
(3, 5), (15,)
(2, 8), (4, 4), (2, 2, 4), (2, 2, 2, 2), (16,)
(17,)
(2, 9), (3, 6), (2, 3, 3), (18,)
(19,)
(2, 10), (4, 5), (2, 2, 5), (20,)
(3, 7), (21,)
(2, 11), (22,)
(23,)
(2, 12), (3, 8), (4, 6), (2, 2, 6), (2, 3, 4), (2, 2, 2, 3), (24,)
(5, 5), (25,)
(2, 13), (26,)
(3, 9), (3, 3, 3), (27,)
(2, 14), (4, 7), (2, 2, 7), (28,)
(29,)
(2, 15), (3, 10), (5, 6), (2, 3, 5), (30,)
(31,)

Funziona anche questo? C'è un caso di test 4 -> {2, 2}, {4}in questione, non vedo tale output nel tuo registro.
Borsunho,

@Borsunho Mentre riavvolgo la vecchia versione, ho dimenticato di aggiungere +1 a int(math.log(n,2)), il che ha causato questo. +2 byte e funzionerà. Grazie!
Yytsi il

Non hai importato mathma stai utilizzando math.log.
orlp,

@orlp I have ...? Sulla terza linea.
Yytsi il

@TuukkaX Scusa, ho solo guardato le righe più in alto per le importazioni, dato che sono quasi sempre lì ... Detto questo, len(bin(n))-2è più breve di int(math.log(n,2)).
orlp,


1

Clojure, 91 byte

(defn f[n](conj(set(for[i(range 2 n):when(=(mod n i)0)j(f(/ n i))](sort(flatten[i j]))))n))

Esempi di esecuzione:

(map f [20 84])
(#{20 (2 2 5) (4 5) (2 10)} #{(7 12) (2 2 3 7) (2 3 14) (2 2 21) (2 6 7) (6 14) (3 4 7) (3 28) (4 21) (2 42) 84})

Il valore stesso viene restituito come un singolo numero (non a list), altri escono come elenchi. Alla nfine potrebbe essere sostituito [n]per renderlo anche una sequenza o (list n)per renderlo un elenco.



0

J, 35 byte

([:~.]<@/:~@(*//.)"$~#\#:i.@!@#)@q:

Basato sulla soluzione di una sfida di fattorizzazione limitata nel tempo.

Questa versione è molto più inefficiente e funziona in tempi fattoriali basati sul numero di fattori primi. Crea partizioni generando numeri fattorici.

Provalo online! (Non provare grandi valori online!)

Spiegazione

([:~.]<@/:~@(*//.)"$~#\#:i.@!@#)@q:  Input: integer n
                                 q:  Prime factorization
(                              )@    Operate on them
                              #        Length
                            !@         Factorial
                         i.@           Range [0, i)
                     #\                Range [1, i]
                       #:              Mixed based conversion - Creates factoradic values
     ]                                 Get factors
            (    )"$~                  For each factoradic value
               /.                        Partition the factors based on equal
                                         digits in the factoradic value
             */                          Get the product of each block
        /:~@                             Sort it
      <@                                 Box it
 [:~.                                  Deduplicate

0

D, 95 byte

void g(int n,int[]r){for(int i=r[0];i*i<=n;i++)(n%i)?0:g(n/i,i~r);r.back=n;r.writeln;}g(n,[2]);

Solo una soluzione ricorsiva. In g(n,r), rè la partizione finora, ed nè ancora il valore lasciato a dividere in fattori. Per ottenere una partizione non ordinata una sola volta, rordiniamo i fattori in ordine non crescente. L'ultimo elemento di rinizia 2come il fattore meno possibile e viene sovrascritto nin ogni copia appena prima di ogni operazione di output.

Per n = 60, l'output è il seguente:

[3, 2, 2, 5]
[2, 2, 15]
[3, 2, 10]
[5, 2, 6]
[2, 30]
[4, 3, 5]
[3, 20]
[4, 15]
[5, 12]
[6, 10]
[60]

Provalo online!


Usa i modelli, Gassa, usa i modelli:void g(T)(T n,T[]r){for(T i=r[0];i*i<=n;i++)n%i0:r;r.back=n;r.writeln;}g(n,[2])
Zacharý

Ad ogni modo, questa non è nemmeno una risposta valida, poiché è necessario importare std.stdioe std.range, in input 1, non deve essere stampato nulla [1].
Zacharý,

0

D, 109 byte

import std.stdio;void g(T)(T n,T[]r=[2]){if(n-1){for(T i=r[0];i*i<=n;i++)n%i?0:g(n/i,i~r);r[$-1]=n;r.write;}}

Provalo online!

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.