Encuentra todas las cadenas de Gozinta distintas

36

Cadenas Gozinta

(Inspirado por el Proyecto Euler # 606 )

Una cadena de gozinta para n es una secuencia {1,a,b,...,n}en la que cada elemento divide adecuadamente al siguiente. Por ejemplo, hay ocho cadenas de 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}.

El reto

Escriba un programa o función que acepte un entero positivo ( n > 1) y genere o devuelva todas las cadenas de gozinta distintas para el número dado.

  1. El orden en las cadenas importa (ascendente), el orden de las cadenas no.
  2. En el caso de que exista una posibilidad remota, no puede usar un dispositivo incorporado que resuelva el desafío.
  3. Este es el .

Editar: Eliminar 1como una entrada potencial.

Paraguas
fuente
44
Bienvenido a PPCG. Buena primera pregunta!
AdmBorkBork
55
"En el azar existe ([¡mirándote, Mathematica!]]"
Erik the Outgolfer
3
Como dijo AdmBorkBork, los casos límite generalmente se agregan solo si son importantes para el núcleo del desafío; si desea una razón solo, [[1]]yo diría que si [1,1]es un gozinta de 1entonces [1,1,12]es un gozinta de lo 12que es [1,1,1,12]y ahora podemos ya no "devolver todo ..."
Jonathan Allan
44
Debes dejar claro el juego de palabras en la pregunta para aquellos que no lo saben. 2|4se lee "dos entra en cuatro", también conocido como "dos gozinta cuatro".
mbomb007
1
Dos horas y media no son suficientes para que funcione el sandbox. Consulte las preguntas frecuentes de sandbox .
Peter Taylor

Respuestas:

10

Python 3 , 68 65 bytes

Editar: -3 bytes gracias a @notjagan

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

Pruébalo en línea!

Explicación

Cada cadena de gozinta consiste en el número xal final de la cadena, con al menos un divisor a la izquierda de la misma. Para cada divisor kde xlas cadenas [1,...,k,x]son distintas. Podemos por lo tanto para cada divisor kencontrar todos sus distintas cadenas gozinta y anexar xal final de las mismas, para obtener todas las distintas cadenas gozinta con kdirectamente a la izquierda de x. Esto se hace de forma recursiva hasta x = 1donde [[1]]se devuelve, ya que todas las cadenas de gozinta comienzan con 1, lo que significa que la recursión ha tocado fondo.

El código se vuelve tan corto debido a la comprensión de la lista de Python que permite la doble iteración. Esto significa que los valores encontrados en f(k)se pueden agregar a la misma lista para todos los divisores diferentes k.

Halvard Hummel
fuente
estaba tratando de hacer esto, demasiado tarde ahora = /
Rod
3
Esta respuesta es increíblemente rápida en comparación con las otras hasta ahora.
ajc2000
-3 bytes eliminando la lista innecesaria de desempaquetado.
notjagan
7

Casco , 13 bytes

ufo=ḣ⁰…ġ¦ΣṖḣ⁰

Un enfoque algo diferente al de H.PWiz , aunque todavía por fuerza bruta. Pruébalo en línea!

Explicación

La idea básica es concatenar todas las subsecuencias [1,...,n]y dividir el resultado en sublistas donde cada elemento divide al siguiente. De estos, mantenemos aquellos que comienzan 1, terminan ny no contienen duplicados. Esto se hace con el "rangify" incorporado . Luego queda descartar duplicados.

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
fuente
Supongo que no es más corto filtrar a las matrices en el conjunto de potencia donde cada número divide al siguiente.
ETHproductions
@ETHproductions No, eso es un byte más .
Zgarb
5

Jalea , 9 8 bytes

ÆḌ߀Ẏ;€ȯ

Pruébalo en línea!

Utiliza una técnica similar a mi respuesta de Japt y, por lo tanto, se ejecuta muy rápidamente en casos de prueba más grandes.

Cómo 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.
ETHproducciones
fuente
4

Mathematica, 77 bytes

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

Forma a Graphdonde los vértices son los Divisorsde la entrada #, y los bordes representan la divisibilidad adecuada, luego encuentra Allcaminos desde el vértice 1hasta el vértice #.

ngenisis
fuente
1
Woah, esto es bastante inteligente!
JungHwan Min
3

Jalea , 12 bytes

ŒPµḍ2\×ISµÐṀ

Un enlace monádico que acepta un entero y devuelve una lista de listas de enteros.

Pruébalo en línea!

¿Cómo?

Queremos todas las listas ordenadas de enteros únicos entre uno y N, de modo que el primero sea uno, el último sea N y todos los pares se dividan. El código logra este filtro al verificar que los criterios de división por pares se satisfacen sobre el conjunto de potencia del rango en cuestión, pero solo selecciona aquellos con sumas máximas de diferencia incremental (los que comienzan con uno y terminan con N tendrán una suma de diferencias incrementales de N-1, otros tendrán 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
fuente
Espera, ¿hay una reducción superpuesta n-sabia? : o cómo nunca vi eso: PI estaba usando <slice>2<divisible>\<each>: P
HyperNeutrino
Usando el cambio más reciente a los rápidos de Jelly, puede usar en Ɲlugar de '2' para 11 bytes .
Sr. Xcoder
3

Japt , 17 bytes

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

¡Pruébelo en línea!

Extrañamente, generar la salida como una cadena fue mucho más fácil que generarlo como una matriz de matrices ...

Explicación

 ⬠£  ß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
ETHproducciones
fuente
Entonces, ¿su enfoque evita generar cadenas inválidas y luego filtrarlas, como lo hacen otros enfoques?
Paraguas
@Umbrella Nope, genera solo los válidos, un divisor a la vez, por lo que funciona a la velocidad del rayo incluso en casos como 12000 :-)
ETHproductions
Muy buen uso de la recursividad :) ¡Y estoy sacando ese ¬truco! : p
Shaggy
@Shaggy ¬es una de las razones por las que he implementado un montón de funciones que son básicamente "hacer X sin argumentos, o Y dado un argumento verdadero": P
ETHproductions
3

Mathematica, 60 bytes

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

Utiliza la forma multi-arg indocumentado de Divisibledonde Divisible[n1,n2,...]vuelve Truesi n2∣n1, n3∣n2y así sucesivamente, y Falsede lo contrario. Tomamos toda Subsetsla lista de Divisorsla entrada #, luego devolvemos Casesla forma {1,___,#}tal que Divisibleda Truela Reversesecuencia d de divisores.

ngenisis
fuente
Entonces, ¿ Divisiblees básicamente una construcción para verificar una cadena de gozinta?
Paraguas
@Umbrella No verifica la divisibilidad adecuada.
ngenisis
3

Haskell, 51 bytes

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

Recurrentemente encuentre cadenas de gozinta de divisores apropiados y anexe n.

Pruébalo en línea!

Christian Sievers
fuente
Siento que debería haber crédito extra por el manejo adecuado 1. Como concluimos colectivamente que estamos exentos 1, ¿podría ahorrar 10 bytes eliminando ese caso?
Paraguas
@Umbrella 1no es un caso especial para este algoritmo, se necesita como caso base para la recursividad. Por sí sola, la segunda ecuación de definición solo puede devolver la lista vacía.
Christian Sievers
Veo. Mi solución (aún no publicada) también se usa [[1]]como base.
Paraguas
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)

Necesita Lambdabot Haskell ya que guardrequiereControl.Monad ser importado. La función principal es una función anónima, que me han dicho que está permitida y elimina un par de bytes.

Gracias a Laikoni por guardar siete bytes.

Explicación:

Las mónadas son muy útiles.

x # y

Esta es nuestra función recursiva que hace todo el trabajo real. xes el número sobre el que estamos acumulando (el producto de los divisores que permanecen en el valor), y yes el siguiente número en el que deberíamos intentar dividirlo.

 | x == y = [[x]]

Si xes igual, yentonces hemos terminado de recurrir. Solo xúselo como el final de la cadena actual de gozinta y devuélvalo.

 | 1 > 0 =

Haskell golf-ism para "Verdadero". Es decir, este es el caso predeterminado.

(guard (mod x y < 1) >>

Estamos operando dentro de la lista mónada ahora. Dentro de la lista de mónadas, tenemos la capacidad de tomar múltiples decisiones al mismo tiempo. Esto es muy útil cuando se encuentra "todo lo posible" de algo por agotamiento. La guarddeclaración dice "solo considere la siguiente opción si una condición es verdadera". En este caso, solo considere la siguiente opción si se ydivide x.

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

Si se ydivide x, tenemos la opción de agregar ya la cadena de gozinta. En este caso, llame recursivamente (#), comenzando de nuevo y = 2con xigual a x / y, ya que queremos "factorizar" lo que yacabamos de agregar a la cadena. Luego, cualquiera que sea el resultado de esta llamada recursiva, multiplique sus valores por los yque acabamos de factorizar y yagreguemos oficialmente a la cadena de gozinta.

++

Considere la siguiente opción también. Esto simplemente agrega las dos listas juntas, pero monádicamente podemos pensar que dice "elegir entre hacer esto o lo otro".

x # (y + 1)

La otra opción es simplemente continuar recurriendo y no usar el valor y. Si yno se divide x, esta es la única opción. Si se ydivide, xentonces se tomará esta opción, así como la otra opción, y los resultados se combinarán.

map (1 :) . (# 2)

Esta es la función principal de gozinta. Comienza la recursión llamando (#)con su argumento. A 1se antepone a cada cadena de gozinta, porque la (#)función nunca los pone en las cadenas.

Silvio Mayolo
fuente
1
¡Gran explicación! Puede guardar algunos bytes colocando los protectores de patrones en una sola línea. mod x y==0se puede acortar a mod x y<1. Debido a que las funciones anónimas están permitidas, su función principal se puede escribir de forma gratuita como 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]

Tal vez hay una mejor condición de terminación (probé algo como

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

pero es más largo) La comprobación de 1parece prudente ya que la limpieza de repeticiones 1o duplicados ( nubno en Prelude) es más bytes.

Pruébalo en línea.

Leif Willerts
fuente
3
(>>=h)para(concatMap h)
Michael Klein
95 bytes
Cristian Lupascu
Mierda, soy estúpido sobre 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<1es falso.

Neil
fuente
2

Jalea , 17 bytes

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

Pruébalo en línea!

Erik el Outgolfer
fuente
Eso fue impresionantemente rápido. Sin 1embargo, su resultado es inesperado. No he logrado encontrar un resultado definitivo para 1, pero supuse que era [[1]]. No puedo decir con certeza que[1,1] sea ​​incorrecto, excepto que todos los demás resultados son secuencias crecientes. Pensamientos?
Paraguas
@Umbrella Es posible que desee dejar que las respuestas hagan cualquier cosa por 1.
Sr. Xcoder
@Umbrella Si es un problema, puedo arreglarlo para +2 (reemplazar ;€con ;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
fuente
FreeQ[...]puede convertirseAnd@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min
¡muy agradable! pero recibo un mensaje adicional DeveloperPartitionMap :: nlen: - Texto del mensaje no encontrado - >> `¿por qué es eso?
J42161217
BlockMapusa la Developer`PartitionMapfunción internamente, pero como es una función de desarrollador, no tiene mensajes de error. El error es causado por las listas que tienen 1 o 0 elementos, con los que no puede hacer 2 particiones.
JungHwan Min
2

Mathematica, 72 bytes

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

Explicación

Divisors@#

Encuentra todos los divisores de la entrada.

Subsets@ ...

Genere todos los subconjuntos de esa lista.

Cases[ ... ]

Elija todos los casos que coincidan con el patrón ...

{1,___,#}

Comenzando con 1 y terminando con <input>...

?( ... )

y satisface la condición ...

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

El elemento izquierdo divide el elemento derecho para todas las 2 particiones de la lista, desplazamiento 1.

JungHwan Min
fuente
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

Explicación

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.

Podría guardar otros 5 bytes si se permite salir con un error en lugar de con gracia, eliminando la verificación Ans> 1 y la condición del bucle. Pero no estoy seguro de que eso esté permitido.

calc84maniac
fuente
¿Escribiste esto en tu calculadora? Porque eso es inesperado y algo impresionante.
Paraguas
¡Sí! La parte difícil de TI-BASIC es que solo hay variables globales, por lo que tuve que usar la lista de manera efectiva como mi pila de recursión.
calc84maniac
2

Mathematica 86 77 Bytes

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

Fuerza bruta por la definición.

Deseando que hubiera una forma más corta de hacer una comparación de elementos secuenciales por pares de una lista.

Gracias a @Jenny_mathy y @JungHwanMin por las sugerencias para guardar 9 bytes

Kelly Lowder
fuente
1
puede usar FreeQ[#∣#2&@@@Partition[#,2,1],1>2]&](como segundo argumento) para ir a 82 bytes
J42161217
@Jenny_mathy O mejor,And@@BlockMap[#∣#2&@@#&,#,2,1]
JungHwan Min
1

Casco , 17 16 bytes

-1 byte, gracias a Zgarb

foEẊ¦m`Je1⁰Ṗthḣ⁰

Pruébalo en línea!

H.PWiz
fuente
Corto, pero lento. Puse 50la entrada y expiró. ¿Cuál es la esencia de su enfoque?
Paraguas
Básicamente, trata todas las cadenas posibles y elige las que coinciden con la especificación
H.PWiz
@Umbrella TIO tiene un tiempo de espera de 60 segundos, no es culpa del programa.
Erik the Outgolfer
o`:⁰:1puede ser`Je1⁰
Zgarb
@Zgarb Una vez más ...
H.PWiz
0

PHP 147 141

Editado para eliminar una prueba 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 repetitivo :(

    $r = [[1]];

Inicie el conjunto de resultados a [[1]]medida que cada cadena comience con 1. Esto también lleva a admitir 1 como entrada.

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

Para cada número del 2 al $i, vamos a extender cada cadena en nuestro conjunto por el número actual si va a ser , luego, agrega la cadena extendida a nuestro conjunto de resultados.

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

Filtra nuestras cadenas intermedias que no llegaron a $i

    return $R;
}

10 caracteres de repetitivo :(

Paraguas
fuente
-1

Mathematica

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

La respuesta se almacena en caché para llamadas adicionales.

Tronco
fuente
1
Bienvenido al sitio! Este es un código de golf, por lo que debe incluir su conteo de bytes y, además, intentar eliminar todos los espacios en blanco adicionales, lo que sospecho que tiene.
Wheat Wizard