Listar todas as partições multiplicativas de n

28

Dado um número positivo n , imprima todas as partições multiplicativas distintas de n em qualquer formato conveniente.

Uma partição multiplicativa de n é um conjunto de números inteiros, todos maiores que um, de modo que seu produto seja n . Por exemplo, 20 possui as seguintes partições multiplicativas distintas:

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

A ordem não importa, assim 2 * 2 * 5como a mesma partição que 2 * 5 * 2.


Exemplos:

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}
orlp
fonte

Respostas:

6

Braquilog , 16 bytes

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

Esta é uma função (não um programa completo) que recebe um número positivo como entrada e gera todas as partições multiplicativas. (Eu também evitei usar quaisquer fatores de fatoração primários embutidos nesta solução, principalmente porque não tinha certeza de que eles ajudariam; eu poderia tentar uma solução mais pesada demais em algum momento.)

Experimente online! (Foi adicionado um código extra à função aqui para transformá-lo em um programa completo; se você fornecer a função mostrada acima diretamente ao TIO, ela executará a função, mas não imprimirá sua saída em nenhum lugar, o que é meio inútil como demonstração .)

Este programa realmente me decepciona, porque grande parte dele está contornando erros no intérprete Brachylog e deficiências em suas especificações, em vez de realmente resolver o problema; mas o intérprete é o que é. (Mesmo com um programa como esse, o intérprete usa muito mais memória do que logicamente deveria e trava devido à exaustão da memória, mas, felizmente, em pequenos problemas, consegue produzir primeiro a saída desejada.) Em uma hipotética "versão perfeita do Brachylog" você poderia escrever ~*.o.:{>1}a,, o que seria 4 bytes mais curto, mas eu precisava adicionar restrições extras para ajudar um pouco o intérprete. (Eu realmente não gosto muito do Brachylog e preferiria o Prolog, mas ele precisava de dicas semelhantes para fazer o programa funcionar e eles demoram muito mais para escrever. Então é o Brachylog.)

Explicação:

Como sempre, um programa Brachylog é um conjunto de restrições; por padrão, a primeira restrição restringe a entrada contra um desconhecido (que chamarei de A ), a segunda restrição restringe A contra um segundo B desconhecido , e assim por diante até chegarmos à saída. Alguns caracteres, como {}, podem alterar esse fluxo geral, portanto, uso um conjunto diferente de letras (por exemplo, X / Y ) para representar incógnitas em predicados aninhados.

>       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

Ainda não está claro como o programa funciona, então vamos tentar simplificar um pouco as restrições. C , D , G , H e I são todos iguais (e iguais à saída). E e F também são os mesmos (e iguais à entrada). Portanto, nossas restrições se resumem a isso:

  • A é o comprimento de B e da saída e é menor que a entrada.
  • B consiste em todos os 1s e não é particularmente útil (faz parte do programa simplesmente porque no intérprete Brachylog existente, :{1<}aprecisa do argumento esquerdo para ter um comprimento restrito ou o intérprete entra em um loop infinito).
  • A saída consiste inteiramente em números maiores que 1 (ou seja, maiores que o elemento correspondente de B ).
  • O produto dos elementos da saída é igual à entrada.
  • A saída é inalterada, classificando-a (ou seja, está na ordem de classificação).

Aliás, não especifiquei explicitamente que todos os elementos da saída são números inteiros, algo que pode parecer necessário; no entanto, o solucionador de restrições do Brachylog não pode lidar com não-números inteiros; portanto, produz convenientemente apenas as soluções que envolvem números inteiros.

Claramente, "o comprimento da saída é menor que a entrada" será verdadeiro sempre que a saída for uma partição multiplicativa da entrada (porque 2 x > x para todo x não negativo , ou seja, 2 x positivo ). Portanto, podemos desconsiderar essa restrição; existe apenas para fornecer ao intérprete Brachylog uma estratégia de trabalho para avaliar o programa. As outras restrições (que a saída é classificada, que seu produto é a entrada e que todos os seus elementos são maiores que 1) são a definição de uma partição multiplicativa e, portanto, essa função é basicamente apenas uma implementação direta da questão.


fonte
6

Braquilog 1, 14 bytes

:{$pp~c:*ao}fd

Experimente online!

Braquilog 2, 11 10 bytes, desafio de pós-datas de idiomas

{ḋp~c×ᵐo}ᵘ

Experimente online!

Maltysen respondeu a essa pergunta em 17 bytes de Pyth, então criei uma solução Brachylog de 16 bytes que funcionava traduzindo a especificação da pergunta para Brachylog. Enquanto eu fazia isso, Dennis escreveu uma solução Jelly de 15 bytes. Então eu tive que descer para 14 bytes. Essa é uma função que aceita a entrada como argumento e retorna uma lista de todas as partições (em vez de um gerador, como na minha outra solução).

Algum tempo depois de escrever essa resposta, Dennis e eu conseguimos reduzir a solução Jelly de maneira cooperativa para 11 bytes. Acontece que há uma nova versão do Brachylog, com uma sintaxe de terser; ele é pós-datado, portanto não conta, mas pode gerenciar o total de 11 bytes muito logo que for lançado; revisões posteriores do idioma (inspiradas em outros desafios) podem chegar a 10, como pode ser visto aqui. Os dois programas são idênticos, com a única diferença sendo a sintaxe.

Ao contrário da minha outra solução, que não utilizava muito as "primitivas do golfe", mas afirmava o problema diretamente, ela ignora praticamente todo o poder das restrições de Brachylog e faz sua melhor impressão de geléia, escrevendo uma cadeia de restrições para a qual o argumento da esquerda já é conhecido (e, portanto, as restrições simplesmente agem como mônadas de geléia em vez de restrições completas). Portanto, ele usa o mesmo algoritmo da solução Pyth do @ Maltysen, que é provavelmente a maneira mais fácil de resolver isso usando as primitivas de golfe típicas. (Curiosamente, a solução "apenas indique o problema" em minha outra resposta seria mais curta se não fosse por bugs / deficiências no intérprete Brachylog, apesar da falta de uso de primitivas de golfe. Algum dia eu preciso escrever um "Brachylog aprimorado" para obter uma boa solução para esse tipo de problema; como os idiomas do golfe, o Brachylog é realmente muito detalhado.)

O programa consiste em um gerador e um invólucro em torno dele. Primeiro, aqui está uma explicação do gerador:

$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

Isso quase resolve o problema, mas acabamos gerando muitas partições muitas vezes cada. Portanto, precisamos de um invólucro para desduplicar as soluções:

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

{…}ᵘ      Convert generator to list of unique elements

fonte
Por que não editar sua resposta exsting?
Downgoat
3
@ Downgoat: As duas respostas usam abordagens completamente diferentes; os algoritmos são diferentes, os recursos de linguagem usados ​​são na maioria independentes e semelhantes. Não faria sentido substituir o mais antigo pelo mais novo (e eu poderia muito bem ter postado o novo, mesmo que fosse mais longo). Esta meta post sugere que é preferível postar respostas separadas nesse tipo de situação.
1
Não sei se você sabe disso, mas pode recuperar a saída definindo o argumento no TIO como uma variável (ou seja, uma letra maiúscula). Por exemplo .
Fatalize
5

Mathematica, 61 bytes

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

Define um operador unário (recursivo) ±que retorna a lista de partições.

Martin Ender
fonte
O mathematica não requer o ponto e vírgula no final?
Pavel
@ Pavel não, o ponto e vírgula suprime a saída no notebook interativo. Obrigado por apontar isso, btw, acidentalmente deixei um ponto e vírgula no final.
Martin Ender
4

Pitão - 17 bytes

Toma todas as permutações da fatoração primária, depois particiona cada uma delas e depois produz todas as partições, mantendo apenas partições distintas.

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

Conjunto de Teste .

Maltysen
fonte
4

Python 2, 70 bytes

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]

Produz uma lista de listas classificadas. Por exemplo f(20)é [[2, 2, 5], [2, 10], [4, 5], [20]].

xnor
fonte
Como o tipo inteiro interno do Python não tem limites, o ponto flutuante não é uma solução aceitável, pois as imprecisões quebram a resposta para entradas muito grandes.
orlp
@orlp Ok, de volta ao Python 2 então.
Xnor
TL; DR Eu acho que 998 não é uma entrada muito grande ;-) IMO é um código muito legal, mais parecido com latência O(n)e comparar com o concorrente Python 2 pode ser mais O(n^4)estiloso - enquanto f (998) pode danificar a memória ou o hardware pode morrer dentro do prazo tempo de aproximadamente 80 dias com o outro algoritmo, este aqui converge após aprox. 7 mili segundos na minha máquina para produzir o resultado [[2, 499], [998]]. IMO o problema poderia ser mais que, para N > 998o RecursionError: maximum recursion depth exceeded in comparisonpára acima Python 3 código ... golfe feliz :-)
Dilettant
@Dilettant Não tenho certeza se isso O(n^4)é suficiente para o envio do meu Python2: D Considerando o caso de teste 998, meu código será executado 9 vezes e calculará a (n+r-1)! / r! / (n-1)!quantidade de tuplas de cada vez, onde rcresce linearmente de 2 e n é 9 - 2. Mas ei, pelo menos você não precisa ajustar o limite de recursão ...
Yytsi 27/12/16
@TuukkaX Advertência: Eu não analisei o código, apenas analisei e comparei o desenvolvimento de tempos de execução entre os dois candidatos a alguns N até 41 anos, depois pensei que eu apenas cometeria o comentário ;-) pilhas e recursões geralmente facilitam, mas depois chamar para questões do tipo como profundas em situações desagradáveis ... espero que eu cunhou o suficiente difusa para a quantidade de pesquisa que entrou.
Dilettant
3

Geléia , 14 13 11 bytes

Ḋx³ŒPQP=¥Ðf

Experimente online!

Eu tinha quase certeza de que a solução Jelly @ Dennis poderia ser melhorada. Infelizmente, não consegui bater o recorde do Brachylog, mas consegui empatá-lo. Atualização : com a ajuda do @Dennis, ela melhorou agora; Eu acho que Jelly pega de volta a coroa.

Este programa é incrivelmente ineficiente, com desempenho de O (2 n 2 ) (é por isso que o caso de teste acima o mostra para a entrada 4). É concluído rapidamente em 4, muito lentamente em 5 e pode não ser praticamente possível executar para números maiores.

Curiosamente, o Brachylog foi aprimorado passando de uma solução que descreveu o problema (no qual Brachylog é bom) para uma solução que usou um algoritmo baseado em fatorar a entrada (no qual Jelly é bom); Enquanto isso, a solução Jelly foi aprimorada, afastando-se de seus pontos fortes e retornando a uma solução que apenas descreve o problema.

Explicação:

Ḋ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

Como a saída de Ḋxé classificada, cada subsequência também deve ser classificada e, portanto, não precisamos classificá-las individualmente. Portanto, a parte "a mesma saída em ordens diferentes é uma duplicata" do problema e os "todos os valores na saída são> 1" parte do problema, resolvidos pela geração. Além disso, o que estamos fazendo basicamente aqui é "encontrar todas as listas para as quais P=³", o que fazemos (de uma maneira incrivelmente ineficiente) gerando todas as listas em questão e filtrando as incorretas.

(Claramente, alguém precisa inventar um híbrido de Jelly e Brachylog, além de um solucionador de restrições realmente bom , para que possamos escrever algo ao longo das linhas de {P=³}~mais algum código de deduplicação e resolver o programa em um tamanho muito mais curto. a alguma distância, no entanto.)


fonte
Por favor, alguém encontre um personagem de economia aqui. Eu adoraria uma "guerra de bytes", na qual as entradas continuarão diminuindo um byte a cada vez. Há bytes suficientes desperdiçados em partes estruturais do programa aqui que parece que isso pode ser improvável.
1
Heh, eu estava prestes a postar algo surpreendentemente semelhante. (Deve atualizar com mais frequência.) 2rPode se tornar e P=³$$pode se tornar P=¥.
Dennis
P=¥não funciona quando o tento no intérprete, embora não tenha muita certeza do porquê (logicamente, deve funcionar, e foi uma das coisas que tentei ao escrever a postagem; tentei novamente para ter certeza, definitivamente não faz o que eu esperava). faz, embora, então eu acho que não é o nosso único byte poupança :-)
1
Não prestou atenção a outro detalhe. Você teria que substituir µcom ¹, bem, como µfaz a gama repetiu o novo argumento esquerdo.
Dennis
Ah, claro. Então agora estamos com 11, com muito menos personagens, o que me faz sentir muito melhor. (Eu usei ³em vez de ¹apenas para a variedade.)
2

JavaScript (ES6), 74 67 bytes

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)));

Resolva diretamente o problema de forma recursiva: para cada número m de 2 a n , pegamos cada partição de n / m com um elemento mínimo de m (para evitar partições duplicadas) e anexamos m . (Para qualquer m que não divida n , isso fornece a matriz vazia, pois nenhum arranjo de números inteiros se multiplica para um decimal.) Definimos um caso base da matriz vazia para 1 , a fim de evitar recursões infinitas.

ETHproductions
fonte
1

Python2, 198 191 172 180 bytes

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]

Um programa completo. Isso pode ser melhorado muito, então sugestões são muito bem-vindas!

Saídas do intervalo de 1 a 31 (inclusive):

(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,)
Yytsi
fonte
Isso funciona mesmo? Há um caso de teste 4 -> {2, 2}, {4}em questão, não vejo essa saída no seu log.
Borsunho
@Borsunho Ao reverter a versão antiga, esqueci de adicionar +1 a int(math.log(n,2)), o que causou isso. +2 bytes e funcionará. Obrigado!
Yytsi
Você não importou, mathmas está usando math.log.
orlp
@orlp eu tenho ...? Na terceira linha.
21716 Yytsi
@TuukkaX Desculpe, eu só olhei para as principais linhas de importação, pois elas estão quase sempre lá ... Dito isto, len(bin(n))-2é mais curto que int(math.log(n,2)).
orlp
1

Clojure, 91 bytes

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

Exemplo é executado:

(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})

O valor em si é retornado como um número único (não a list), outros são exibidos como listas. O nfinal poderia ser substituído por [n]para torná-lo uma sequência também ou (list n)para fazer uma lista.

NikoNyrh
fonte
0

J, 35 bytes

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

Baseado na solução para um desafio de fatoração com restrição de tempo.

Esta versão é muito mais ineficiente e funciona em tempo fatorial com base no número de fatores primos. Cria partições gerando números fatorádicos.

Experimente online! (Não tente grandes valores online!)

Explicação

([:~.]<@/:~@(*//.)"$~#\#: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
milhas
fonte
0

D, 95 bytes

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]);

Apenas uma solução recursiva. Em g(n,r), restá a partição até o momento e ainda né o valor a ser dividido em fatores. Para obter cada partição não ordenada apenas uma vez, ordenamos os fatores em rordem não crescente. O último elemento rcomeça com 2o menor fator possível e é substituído por ncada cópia imediatamente antes de cada operação de saída.

Para n = 60, a saída é a seguinte:

[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]

Experimente online!

Gassa
fonte
Use os modelos, Gassa, use os modelos: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ý
De qualquer forma, essa nem é uma resposta válida, pois você precisa importar std.stdioe std.range, a entrada não 1deve imprimir nada, não [1].
Zachary
0

D, 109 bytes

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

Experimente online!

Zacharý
fonte