Encontre todas as cadeias distintas de Gozinta

36

Correntes de Gozinta

(Inspirado no Projeto Euler # 606 )

Uma cadeia gozinta para n é uma sequência em {1,a,b,...,n}que cada elemento divide adequadamente o próximo. Por exemplo, existem oito cadeias gozinta distintas para 12:

{1,12}, {1,2,12}, {1,2,4,12}, {1,2,6,12}, {1,3,12}, {1,3,6,12}, {1,4,12} and {1,6,12}.

O desafio

Escreva um programa ou função que aceite um número inteiro positivo ( n > 1) e produza ou retorne todas as cadeias gozinta distintas para o número fornecido.

  1. A ordem nas cadeias é importante (ascendente), a ordem das cadeias não.
  2. Na eventualidade de existir, você não pode usar um componente interno que resolva o desafio.
  3. Isso é .

Editar: Removendo 1como uma entrada potencial.

Guarda-chuva
fonte
4
Bem-vindo ao PPCG. Boa primeira pergunta!
AdmBorkBork
5
"Por acaso existe [(olhando para você, Mathematica!)]"
Erik, o Outgolfer
3
Como o AdmBorkBork disse, os casos extremos geralmente são adicionados apenas se forem importantes para o âmago do desafio - se você quiser um motivo apenas, [[1]]eu diria que se [1,1]é uma gozinta de 1então [1,1,12]é uma gozinta de 12como é [1,1,1,12]e agora podemos não "retorne tudo ..."
Jonathan Allan
4
Você deve deixar claro o trocadilho na pergunta para quem não o conhece. 2|4é lido "dois entra em quatro" aka "dois gozinta quatro".
mbomb007
1
Duas horas e meia não é tempo suficiente para a caixa de areia funcionar. Veja as perguntas frequentes sobre o sandbox .
Peter Taylor

Respostas:

10

Python 3 , 68 65 bytes

Edit: -3 bytes graças a @notjagan

f=lambda x:[y+[x]for k in range(1,x)if x%k<1for y in f(k)]or[[x]]

Experimente online!

Explicação

Cada cadeia gozinta consiste no número xno final da cadeia, com pelo menos um divisor à esquerda dela. Para cada divisor kdas xcadeias [1,...,k,x]são distintos. Podemos, portanto, para cada divisor kencontrar todas as suas distintas correntes gozinta e acrescentar xao final deles, para obter todas as distintas cadeias gozinta com kdiretamente à esquerda da x. Isso é feito recursivamente até x = 1onde [[1]]é retornado, pois todas as cadeias gozinta começam com 1, o que significa que a recursão atingiu o fundo do poço.

O código se torna tão curto devido à compreensão da lista do Python, permitindo a iteração dupla. Isso significa que os valores encontrados em f(k)podem ser adicionados à mesma lista para todos os diferentes divisores k.

Halvard Hummel
fonte
estava tentando fazer isso, muito tarde agora = /
Rod
3
Esta resposta é incrivelmente rápida em comparação com as outras até agora.
precisa saber é
-3 bytes removendo a lista desnecessária da descompactação.
precisa saber é o seguinte
7

Casca , 13 bytes

ufo=ḣ⁰…ġ¦ΣṖḣ⁰

Uma abordagem um pouco diferente da de H.PWiz , embora ainda por força bruta. Experimente online!

Explicação

A idéia básica é concatenar todas as subsequências [1,...,n]e dividir o resultado em sublistas, onde cada elemento divide o próximo. Destes, mantemos aqueles que começam com 1, terminam ne não contêm duplicatas. Isso é feito com o "rangify" embutido . Resta então descartar as duplicatas.

ufo=ḣ⁰…ġ¦ΣṖḣ⁰  Input is n=12.
           ḣ⁰  Range from 1: [1,2,..,12]
          Ṗ    Powerset: [[],[1],[2],[1,2],[3],..,[1,2,..,12]]
         Σ     Concatenate: [1,2,1,2,3,..,1,2,..,12]
       ġ¦      Split into slices where each number divides next: [[1,2],[1,2],[3],..,[12]]
 fo            Filter by
      …        rangified
   =ḣ⁰         equals [1,...,n].
u              Remove duplicates.
Zgarb
fonte
Eu acho que não é mais curto filtrar para as matrizes no conjunto de energia em que cada número divide o próximo?
ETHproductions
@ETHproductions Não, é um byte a mais .
Zgarb
5

Geléia , 9 8 bytes

ÆḌ߀Ẏ;€ȯ

Experimente online!

Utiliza uma técnica semelhante à minha resposta em japonês e, portanto, é executada muito rapidamente em casos de teste maiores.

Como funciona

ÆḌ߀Ẏ;€ȯ    Main link. Argument: n (integer)
ÆḌ          Yield the proper divisors of n.
       ȯ    If there are no divisors, return n. Only happens when n is 1.
  ߀        Otherwise, run each divisor through this link again. Yields
            a list of lists of Gozinta chains.
    Ẏ       Tighten; bring each chain into the main list.
     ;€     Append n to each chain.
ETHproductions
fonte
4

Mathematica, 77 bytes

FindPath[Graph@Cases[Divisors@#~Subsets~{2},{m_,n_}/;m∣n:>m->n],1,#,#,All]&

Forma a Graphonde os vértices são os Divisorsda entrada #e as arestas representam a divisibilidade adequada e, em seguida, localiza Allcaminhos do vértice 1para o vértice #.

ngenisis
fonte
1
Uau, isso é muito inteligente!
JungHwan Min 15/08/19
3

Gelatina , 12 bytes

ŒPµḍ2\×ISµÐṀ

Um link monádico que aceita um número inteiro e retorna uma lista de listas de números inteiros.

Experimente online!

Quão?

Queremos todas as listas classificadas de números inteiros únicos entre um e N, de modo que o primeiro seja um, o último seja N e todos os pares se dividam. O código alcança esse filtro verificando se os critérios de divisão por pares são satisfeitos no conjunto de potência do intervalo em questão, mas apenas escolhendo aqueles com somas máximas de diferença incremental (os que começam com um e terminam com N terão soma das diferenças incrementais de N-1, outras terão menos).

ŒPµḍ2\×ISµÐṀ - Link: number N
ŒP           - power-set (implicit range of input) = [[1],[2],...,[N],[1,2],[1,3],...,[1,N],[1,2,3],...]
          ÐṀ - filter keep those for which the result of the link to the left is maximal:
  µ      µ   - (a monadic chain)
    2\       -   pairwise overlapping reduce with:
   ḍ         -     divides? (1 if so, 0 otherwise)
       I     -   increments  e.g. for [1,2,4,12] -> [2-1,4-2,12-4] = [1,2,8]
      ×      -   multiply (vectorises) (no effect if all divide,
             -                          otherwise at least one gets set to 0)
        S    -   sum         e.g. for [1,2,4,12] -> 1+2+8 = 11 (=12-1)
Jonathan Allan
fonte
Espere, há redução de sobreposição n-wise? : o como é que eu nunca ver que: PI estava usando <slice>2<divisible>\<each>: P
HyperNeutrino
Usando as alterações mais recentes nas rápidas do Jelly, você pode usar em Ɲvez de `2 'por 11 bytes .
Sr. Xcoder
3

Japonês , 17 bytes

⬣ßX m+S+UR÷ª'1

Teste online!

Estranhamente, gerar a saída como uma string era muito mais fácil do que gerá-la como uma matriz de matrizes ...

Explicação

 ⬠£  ßX m+S+URà ·  ª '1
Uâq mX{ßX m+S+UR} qR ||'1   Ungolfed
                            Implicit: U = input number, R = newline, S = space
Uâ                          Find all divisors of U,
  q                           leaving out U itself.
    mX{         }           Map each divisor X to
       ßX                     The divisor chains of X (literally "run the program on X")
          m    R              with each chain mapped to
           +S+U                 the chain, plus a space, plus U.
                  qR        Join on newlines.
                     ||     If the result is empty (only happens when there are no factors, i.e. U == 1)
                       '1     return the string "1".
                            Otherwise, return the generated string.
                            Implicit: output result of last expression
ETHproductions
fonte
Então, sua abordagem evita gerar cadeias inválidas e depois filtrá-las, como outras abordagens?
Umbrella
@Umbrella Não, ele gera apenas os válidos, um divisor de cada vez, portanto, por que ela funciona extremamente rápido, mesmo em casos como 12000 :-)
ETHproductions
Uso muito bom da recursão :) E estou cortando esse ¬truque! : p
Shaggy
@Shaggy ¬é uma das razões pelas quais eu já implementados um monte de funções que são basicamente "fazer X dado sem argumentos, ou Y dado um argumento truthy": P
ETHproductions
3

Mathematica, 60 bytes

Cases[Subsets@Divisors@#,x:{1,___,#}/;Divisible@@Reverse@{x}]&

Usa a forma multi-arg não documentada de Divisibleonde Divisible[n1,n2,...]retorna Truese n2∣n1, n3∣n2e assim por diante, e Falsede outra forma. Pegamos toda Subsetsa lista de Divisorsentradas e #, em seguida, retornamos Casesa forma {1,___,#}que Divisiblefornece Truea Reversesequência d dos divisores.

ngenisis
fonte
Então, Divisibleé basicamente um builtin para verificar uma cadeia de gozinta?
Umbrella
@Umbrella Não verifica a divisibilidade adequada.
Ngenisis
3

Haskell, 51 bytes

f 1=[[1]]
f n=[g++[n]|k<-[1..n-1],n`mod`k<1,g<-f k]

Encontre recursivamente cadeias gozinta de divisores adequados e acrescente n.

Experimente online!

Peneiradores cristãos
fonte
Sinto que deve haver crédito extra para o manuseio adequado 1. Como concluímos a isenção coletivamente 1, você poderia economizar 10 bytes removendo esse caso?
Umbrella
O @Umbrella 1não é um caso especial para esse algoritmo, é necessário como caso base para a recursão. Por si só, a segunda equação que define apenas pode retornar a lista vazia.
Christian Sievers
Entendo. Minha solução (ainda não publicada) usa [[1]]como base também.
Umbrella
3

Haskell (Lambdabot), 92 85 bytes

x#y|x==y=[[x]]|1>0=(guard(mod x y<1)>>(y:).map(y*)<$>div x y#2)++x#(y+1)
map(1:).(#2)

Precisa do Lambdabot Haskell, pois guardrequer Control.Monadque seja importado. A função principal é uma função anônima, que me disseram que é permitida e retira alguns bytes.

Agradecemos a Laikoni por salvar sete bytes.

Explicação:

Mônadas são muito úteis.

x # y

Esta é a nossa função recursiva que faz todo o trabalho real. xé o número que estamos acumulando (o produto dos divisores que permanecem no valor) e yé o próximo número que devemos tentar dividir nele.

 | x == y = [[x]]

Se for xigual y, terminamos de repetir. Basta usar xcomo o final da corrente gozinta atual e devolvê-lo.

 | 1 > 0 =

Haskell golf-ism para "True". Ou seja, este é o caso padrão.

(guard (mod x y < 1) >>

Estamos operando dentro da lista mônada agora. Na mônada da lista, temos a capacidade de fazer várias escolhas ao mesmo tempo. Isso é muito útil ao encontrar "tudo possível" de algo por exaustão. A guarddeclaração diz "considere apenas a seguinte opção se uma condição for verdadeira". Nesse caso, considere apenas a seguinte opção se ydividir x.

(y:) . map (y *) <$> div x y#2)

Se ydividir x, temos a opção de adicionar yà cadeia gozinta. Nesse caso, chame recursivamente (#), começando y = 2com xigual a x / y, pois queremos "fatorar" que yacabamos de adicionar à cadeia. Então, qualquer que seja o resultado dessa chamada recursiva, multiplique seus valores pelo yque acabamos de yfatorar e adicione oficialmente à cadeia gozinta.

++

Considere a seguinte opção também. Isso simplesmente adiciona as duas listas, mas, monadicamente, podemos pensar nisso como dizendo "escolha entre fazer essa coisa OU essa outra coisa".

x # (y + 1)

A outra opção é simplesmente continuar recorrendo e não usar o valor y. Se ynão se dividir x, esta é a única opção. Se ydividir x, esta opção será usada, assim como a outra opção, e os resultados serão combinados.

map (1 :) . (# 2)

Esta é a principal função gozinta. Inicia a recursão chamando (#)com seu argumento. A 1é anexado a todas as cadeias gozinta, porque a (#)função nunca as coloca nas cadeias.

Silvio Mayolo
fonte
1
Ótima explicação! Você pode salvar alguns bytes colocando todos os protetores de padrão em uma linha. mod x y==0pode ser reduzido para mod x y<1. Como funções anônimas são permitidas, sua função principal pode ser escrita como pointfree map(1:).(#2).
Laikoni
3

Haskell, 107 100 95 bytes

f n=until(all(<2).map head)(>>=h)[[n]]
h l@(x:_)|x<2=[l]|1<2=map(:l)$filter((<1).mod x)[1..x-1]

Talvez exista uma melhor condição de terminação (tentei algo como

f n=i[[n]]
i x|g x==x=x|1<2=i$g x
g=(>>=h)

mas é mais longo). A verificação 1parece prudente, pois a repetição 1ou eliminação de repetições (ou nubnão Prelude) é mais bytes.

Experimente online.

Leif Willerts
fonte
3
(>>=h)for(concatMap h)
Michael Klein
95 bytes
Cristian Lupascu
Caramba eu sou sobre estúpido u...
Leif Willerts
3

JavaScript (Firefox 30-57), 73 bytes

f=n=>n>1?[for(i of Array(n).keys())if(n%i<1)for(j of f(i))[...j,n]]:[[1]]

Convenientemente n%0<1é falso.

Neil
fonte
2

Geléia , 17 bytes

ḊṖŒP1ppWF€ḍ2\Ạ$Ðf

Experimente online!

Erik, o Outgolfer
fonte
Isso foi impressionantemente rápido. Seu resultado para 1é inesperado, no entanto. Não consegui encontrar um resultado definitivo para 1, mas presumi que fosse [[1]]. Não posso dizer com certeza que isso [1,1]esteja incorreto, exceto que todos os outros resultados são sequências crescentes. Pensamentos?
Umbrella
@Umbrella Você pode querer deixar as respostas fazer qualquer coisa para 1.
Mr. Xcoder
@ Guarda-chuva Se houver algum problema, posso corrigi-lo para +2 (substitua ;€por ;Q¥€).
Erik the Outgolfer
2

Mathematica, 104 bytes

(S=Select)[Rest@S[Subsets@Divisors[t=#],FreeQ[#∣#2&@@@Partition[#,2,1],1>2]&],First@#==1&&Last@#==t&]&
J42161217
fonte
FreeQ[...]pode se tornarAnd@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min
muito agradável! mas recebo uma mensagem extra DeveloperPartitionMap :: nlen: - Texto da mensagem não encontrado - >> `por que isso?
J42161217
BlockMapusa a Developer`PartitionMapfunção internamente, mas como é uma função de desenvolvedor, não possui mensagens de erro. O erro é causado pelas listas que possuem 1 ou 0 elementos, com os quais você não pode criar 2 partições.
JungHwan Min 15/08/19
2

Mathematica, 72 bytes

Cases[Subsets@Divisors@#,{1,___,#}?(And@@BlockMap[#∣#2&@@#&,#,2,1]&)]&

Explicação

Divisors@#

Encontre todos os divisores da entrada.

Subsets@ ...

Gere todos os subconjuntos dessa lista.

Cases[ ... ]

Escolha todos os casos que correspondem ao padrão ...

{1,___,#}

Começando com 1 e terminando com <input>...

?( ... )

e satisfaz a condição ...

And@@BlockMap[#∣#2&@@#&,#,2,1]&

O elemento esquerdo divide o elemento direito para todas as 2 partições da lista, deslocamento 1.

JungHwan Min
fonte
2

TI-BASIC, 76 bytes

Input N
1→L1(1
Repeat Ans=2
While Ans<N
2Ans→L1(1+dim(L1
End
If Ans=N:Disp L1
dim(L1)-1→dim(L1
L1(Ans)+L1(Ans-(Ans>1→L1(Ans
End

Explicação

Input N                       Prompt user for N.
1→L1(1                        Initialize L1 to {1}, and also set Ans to 1.

Repeat Ans=2                  Loop until Ans is 2.
                              At this point in the loop, Ans holds the
                              last element of L1.

While Ans<N                   While the last element is less than N,
2Ans→L1(1+dim(L1              extend the list with twice that value.
End

If Ans=N:Disp L1              If the last element is N, display the list.

dim(L1)-1→dim(L1              Remove the last element, and place the new
                              list size in Ans.

L1(Ans)+L1(Ans-(Ans>1→L1(Ans  Add the second-to-last element to the last
                              element, thereby advancing to the next
                              multiple of the second-to-last element.
                              Avoid erroring when only one element remains
                              by adding the last element to itself.

End                           When the 1 is added to itself, stop looping.

Eu poderia salvar outros 5 bytes se for permitido sair com um erro em vez de normalmente, removendo a verificação Ans> 1 e a condição do loop. Mas não estou confiante de que isso seja permitido.

calc84maniac
fonte
Você digitou isso na sua calculadora? Porque isso é inesperado e algo impressionante.
Umbrella
Sim! A parte complicada do TI-BASIC é que existem apenas variáveis ​​globais, então tive que usar efetivamente a própria lista como minha pilha de recursão.
calc84maniac
2

Mathematica 86 77 Bytes

Select[Subsets@Divisors@#~Cases~{1,___,#},And@@BlockMap[#∣#2&@@#&,#,2,1]&]&

Força bruta pela definição.

Desejando que houvesse uma maneira mais curta de comparar elementos sequenciais em pares de uma lista.

Obrigado a @Jenny_mathy e @JungHwanMin pelas sugestões de salvar 9 bytes

Kelly Lowder
fonte
1
você pode usar FreeQ[#∣#2&@@@Partition[#,2,1],1>2]&](como o segundo argumento) para ir para 82 bytes
J42161217
@Jenny_mathy Or better,And@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min 15/17
1

Casca , 17 16 bytes

-1 byte, graças ao Zgarb

foEẊ¦m`Je1⁰Ṗthḣ⁰

Experimente online!

H.PWiz
fonte
Curto, mas lento. Coloquei 50a entrada e o tempo esgotou. Qual é a essência da sua abordagem?
Umbrella
É essencialmente tenta todas as cadeias possíveis e escolhe aqueles que correspondem a especificação
H.PWiz
O @Umbrella TIO tem um tempo limite de 60 segundos, não é culpa do programa.
Erik the Outgolfer
o`:⁰:1pode ser`Je1⁰
Zgarb
@Zgarb Mais uma vez ...
H.PWiz 15/08
0

PHP 147 141

Editado para remover um teste redundante

function g($i){$r=[[1]];for($j=2;$j<=$i;$j++)foreach($r as$c)if($j%end($c)<1&&$c[]=$j)$r[]=$c;foreach($r as$c)end($c)<$i?0:$R[]=$c;return$R;}

Explicado:

function g($i) {

15 caracteres de clichê :(

    $r = [[1]];

Inicie o conjunto de resultados [[1]]como cada cadeia começa com 1. Isso também leva ao suporte a 1 como uma entrada.

    for ($j = 2; $j <= $i; $j++) {
        foreach ($r as $c) {
            if ($j % end($c) < 1) {
                $c[] = $j;
                $r[] = $c;
            }
        }
    }

Para cada número de 2 a $i, vamos estender cada cadeia em nosso conjunto pelo número atual se ele gozinta , em seguida, adicione a cadeia estendida ao nosso conjunto de resultados.

    foreach ($r as $c) {
        end($c) < $i ? 0 : $R[] = $c;
    }

Filtre nossas cadeias intermediárias que não conseguiram $i

    return $R;
}

10 caracteres de clichê :(

Guarda-chuva
fonte
-1

Mathematica

f[1] = {{1}};
f[n_] := f[n] = Append[n] /@ Apply[Join, Map[f, Most@Divisors@n]]

A resposta é armazenada em cache para chamadas adicionais.

BoLe
fonte
1
Bem vindo ao site! Este é um código-golfe, portanto, você deve incluir sua contagem de bytes e, além disso, tentar remover todo o espaço em branco extra, que eu suspeito que você tenha.
Assistente de trigo