Secuencia de humo fractal


33

Introducción

A229037 tiene una trama bastante intrigante (al menos para los primeros términos):

Existe la conjetura de que podría tener algún tipo de propiedad fractal.

¿Cómo se construye esta secuencia?

Definir a(1) = 1, a(2) = 1entonces para cada n>2encontrar un positivo mínimo número entero a(n)tal que para cada secuencia aritmética 3 plazo n,n+k,n+2kde índices, los valores correspondientes de la secuencia a(n),a(n+k),a(n+2k)es no una secuencia aritmética.

Reto

Dado un entero positivo ncomo entrada, genera los primeros ntérminos a(1), ... , a(n)de esta secuencia. (Con cualquier formato razonable. Los posibles caracteres / cadenas iniciales / formativos son irrelevantes).

Hay fragmentos disponibles para generar esta secuencia, pero creo que otros enfoques podrían ser más fáciles de encontrar / más adecuados para ciertos idiomas.

Por favor, háganos saber cómo funciona su programa. Si se cruza con un algoritmo particularmente eficiente, es posible que desee mencionarlo también, ya que permitiría trazar más términos de la secuencia en un tiempo más corto.

Primeros casos de prueba:

1, 1, 2, 1, 1, 2, 2, 4, 4, 1, 1, 2, 1, 1, 2, 2, 4, 4, 2, 4, 4, 5, 5, 8, 5, 5, 9, 1, 1, 2, 1, 1, 2, 2, 4, 4, 1, 1, 2, 1, 1, 2, 2, 4, 4, 2, 4, 4, 5, 5, 8, 5, 5, 9, 9, 4, 4, 5, 5, 10, 5, 5, 10, 2, 10, 13, 11, 10, 8, 11, 13, 10, 12, 10, 10, 12, 10, 11, 14, 20, 13

Más casos de prueba:

  a(100)  =   4
  a(500)  =   5
 a(1000)  =  55
 a(5000)  =  15
a(10000)  = 585

Todos los términos n=100000disponibles están disponibles aquí: https://oeis.org/A229037/b229037.txt

Gracias @ MartinBüttner por la ayuda y el aliento.


2
Oye, ¿dónde he visto este gráfico antes? :-D
Luis Mendo

12
Mueve la cabeza un poco hacia la izquierda, amplía un poco, ¡ya está! (:
flawr

44
Apareció un video de Numberphile: youtube.com/watch?v=o8c4uYnnNnc
falla

2
¡Apuesto a que su código no es tan golfoso!
Luis Mendo

Respuestas:


12

Python 2, 95 bytes

l=[];n=input()
exec"a=min(set(range(n))-{2*b-c for b,c in zip(l,l[1::2])});print-~a;l=[a]+l;"*n

El truco principal está en generar los números que el nuevo valor debe evitar. Manteniendo la secuencia invertida hasta ahora l, veamos qué elementos podrían formar una progresión aritmética de tres términos con el valor que estamos a punto de agregar.

? 4 2 2 1 1 2 1 1   a b c
^ ^ ^               ? 4 2
^   ^   ^           ? 2 1
^     ^     ^       ? 2 2
^       ^       ^   ? 1 1

Los otros números son los miembros emparejados de ly cada segundo elemento de l, entonces zip(l,l[1::2]). Si este par es, (b,c)entonces (a,b,c)ocurre la progresión aritmética a=2*b-c. Después de generar el conjunto de a's para evitar, el código toma el mínimo del complemento, lo imprime y lo antepone a la lista. (En realidad, el cálculo se realiza con números disminuidos en 1 e impresos 1 más alto, para permitir que range(n)sirva como un universo de candidatos).


8

Mathematica, 95 bytes

For[n_~s~k_=0;n=0,n<#,For[i=n,--i>0,s[2n-i,2f@n-f@i]=1];For[++n;i=1,n~s~i>0,++i];Print[f@n=i]]&

Ciertamente no es el enfoque más golfista, pero en realidad es bastante eficiente, en comparación con los algoritmos que probé en la página OEIS.

En lugar de verificar todos los valores prohibidos para cada s (n) cuando llegamos allí, estoy usando un enfoque basado en tamiz. Cuando encontramos un nuevo valor s (n) verificamos inmediatamente qué valores prohíbe para m> n . Luego, solo resolvemos la s (n + 1) buscando el primer valor que no estaba prohibido.

Esto puede hacerse aún más eficiente cambiando el condicional --i>0a 2n-#<=--i>0. En ese caso, evitamos verificar los valores prohibidos para n mayor que la entrada.

Para una versión algo más legible, comencé con este código, que almacena los resultados hasta maxen una función f, y luego lo llevé a la función pura de una línea anterior:

 max = 1000;
 ClearAll[sieve, f];
 sieve[n_, k_] = False;
 For[n = 0, n < max,
  temp = f[n];
  For[i = n - 1, i > 0 && 2 n - i <= max, --i,
   sieve[2 n - i, 2 temp - f[i]] = True;
   ];
  ++n;
  i = 1;
  While[sieve[n, i], ++i];
  f@n = i;
  ]

3

Haskell, 90 , 89 , 84 , 83 bytes

Probablemente se pueda jugar más al golf, pero este sigue siendo un primer intento decente :

a n|n<1=0|n<3=1|1<2=[x|x<-[1..],and[x/=2*a(n-k)-a(n-k-k)||a(n-k-k)<1|k<-[1..n]]]!!0

Sin golf:

a n | n<1        = 0 
    | n<3        = 1
    | otherwise  = head (goods n)

goods n = [x | x <- [1..], isGood x n]

isGood x n = and [ x - a(n-k) /= a(n-k) - a(n-k-k) || a(n-k-k) == 0 | k <- [1..n] ]

Esta es una implementación simple que devuelve '0' para fuera de los límites. Luego, para cada valor posible, comprueba que para todos k <= n y en los límites, [x, a (xk), a (x-2k)] no es una secuencia aritmética.

Límite superior en la complejidad del tiempo (utilizando el hecho de la página OEIS de que a (n) <= (n + 1) / 2:

t n <= sum[ sum[2*t(n-k) + 2*t(n-k-k) | k <- [1..n]] | x <- [1..(n+1)/2]]
    <= sum[ sum[4*t(n-1)              | k <- [1..n]] | x <- [1..(n+1)/2]]
    <= sum[     4*t(n-1)*n                         ] | x <- [1..(n+1)/2]]
    <=          4*t(n-1)*n*(n+1)/2
    ->
O(t(n)) == O(2^(n-2) * n! * (n+1)!)

No estoy seguro de cuán bueno es este límite porque calcular los primeros valores 1k de 't' y usar un modelo lineal en los registros de los valores dio appx. O (22 ^ n), con valor p <10 ^ (- 1291), en caso de que sea importante.

En un nivel de implementación, compilando con '-O2', tardó ~ 35 minutos en calcular los primeros 20 valores.


1
¿Cuál es la complejidad del tiempo para su programa?
flawr

@flawr Se agregó un análisis de complejidad de tiempo a la publicación
Michael Klein

3

Brachylog , 33 31 bytes

;Ė{~b.hℕ₁≜∧.¬{ġh₃hᵐs₂ᶠ-ᵐ=}∧}ⁱ⁽↔

Pruébalo en línea!

En caso de que sea importante: el golf de 2 bytes fue posible gracias a una función que solicité después de trabajar en este desafío.

Explicación

Generamos iterativamente la secuencia como una lista en orden inverso, por ejemplo [2,2,1,1,2,1,1], y la invertimos al final.

Hay un par de predicados anidados aquí. Miremos de adentro hacia afuera. El primero ġh₃hᵐs₂ᶠ-ᵐ=, toma una subsecuencia candidata a(n),a(n-1),...,a(0)y determina si a(n),a(n-k),a(n-2k)es una secuencia aritmética para algunos k.

ġ            Group the list into equal-length sublists (with the possible exception of
             the last sublist, which might be shorter)
 h₃          Get the first 3 sublists from that list
   hᵐ        and get the head of each of those 3 sublists
             We now have a list containing a(n),a(n-k),a(n-2k) for some k
     s₂ᶠ     Find all 2-element sublists of that list: [a(n),a(n-k)] and [a(n-k),a(n-2k)]
        -ᵐ   Find the difference of each pair
          =  Assert that the two pairwise differences are equal

Por ejemplo, con entrada de [1,2,1,1,2,1,1]:

ġ has possible outputs of
    [[1],[2],[1],[1],[2],[1],[1]]
    [[1,2],[1,1],[2,1],[1]]
    [[1,2,1],[1,2,1],[1]]
    [[1,2,1,1],[2,1,1]]
    [[1,2,1,1,2],[1,1]]
    [[1,2,1,1,2,1],[1]]
    [[1,2,1,1,2,1,1]]
h₃ has possible outputs of
    [[1],[2],[1]]
    [[1,2],[1,1],[2,1]]
    [[1,2,1],[1,2,1],[1]]
hᵐ has possible outputs of
    [1,2,1]
    [1,1,2]
    [1,1,1]
s₂ᶠ has possible outputs of
    [[1,2],[2,1]]
    [[1,1],[1,2]]
    [[1,1],[1,1]]
-ᵐ has possible outputs of
    [-1,1]
    [0,-1]
    [0,0]
= is satisfied by the last of these, so the predicate succeeds.

El siguiente predicado hacia afuera, ~b.hℕ₁≜∧.¬{...}∧ingresa una subsecuencia a(n-1),a(n-2),...,a(0)y genera la siguiente subsecuencia más grande a(n),a(n-1),a(n-2),...,a(0).

~b.hℕ₁≜∧.¬{...}∧
~b.                 The input is the result of beheading the output; i.e., the output is
                    the input with some value prepended
  .h                The head of the output
    ℕ₁              is a natural number >= 1
      ≜             Force a choice as to which number (I'm not sure why this is necessary,
                    but the code doesn't work without it)
        ∧           Also,
         .          the output
          ¬{...}    does not satisfy the nested predicate (see above)
                    I.e. there is no k such that a(n),a(n-k),a(n-2k) is an arithmetic sequence
                ∧   Break unification with the output

Finalmente, el predicado principal ;Ė{...}ⁱ⁽↔toma un número de entrada y genera muchos términos de la secuencia.

;Ė{...}ⁱ⁽↔
;           Pair the input number with
 Ė          the empty list
  {...}ⁱ⁽   Using the first element of the pair as the iteration count and the second
            element as the initial value, iterate the nested predicate (see above)
         ↔  Reverse, putting the sequence in the proper order

3

Ruby , 71 bytes

->n,*a{a.fill(0,n){|s|([*1..n]-(1..s/2).map{|o|2*a[s-o]-a[s-2*o]})[0]}}

Pruébalo en línea!

Genera todos los valores prohibidos, luego toma el complemento de esa matriz en (1..n) y toma el primer valor del resultado. Eso significa que estoy asumiendo que a[n] <= npara todo n, lo cual se prueba fácilmente usando inducción (si los primeros términos n / 2 son todos menores que n / 2, entonces no puede haber una progresión aritmética que conduzca a n).

El truco sintáctico aquí también es ligeramente interesante: *ase utiliza para inicializar una matriz de argumentos adicionales (que se ignorarían si pasáramos alguno), y luego a.fillmuta la matriz de argumentos y la devuelve implícitamente.


1
-1 byte: en lugar de a[s-o]y a[s-2*o], puede usar a[s-=1]ya[s-o]
GB

3

APL (Dyalog Extended) , SBCS de 37 bytes

Muchas gracias a Adám por su ayuda para escribir y jugar golf en esta respuesta en The APL Orchard , un excelente lugar para aprender el idioma APL. Pruébalo en línea!

Editar: -6 bytes gracias a Adám

⌽{⍵,⍨⊃(⍳1+≢⍵)~-¯2⊥⍵[2×⍀⍥⍳⌊2÷⍨≢⍵]}⍣⎕,⍬

Explicación

{⍵,⍨⊃(⍳1+≢⍵)~-¯2⊥⍵[2×⍀⍥⍳⌊2÷⍨≢⍵]}   is our right argument, the sequence S

                        2÷⍨≢⍵    We start by calculating X = len(S2
                                 Get a range [1, X]
                   2×⍀⍥           With that we can get S[:X] and S[:X×2:2]
                                  or S up to halfway and every 2nd element of S
             2⊥⍵[           ]   And with that we can get 2*S[:X] - S[:X×2:2]
                                  Which is C=2*B-A of a progression A B C
     (⍳1+≢⍵)~                     We remove these Cs from our possible a(n)s
                                  I use range [1, len(S)+1]
                                 Get the first result, which is the minimum
 ⍵,⍨                              And then prepend that to S


⌽{...}⍣⎕,⍬

 {...}⍣⎕    We iterate an "input"  times
        ,⍬  with an empty list  as the initial S
           and reversing S at the end as we have built it backwards

APL (Dyalog Unicode) , 43 39 38 bytes SBCS

Aquí hay una solución más rápida pero menos deportiva que puede calcularse ⍺(10000)en unos segundos.

⌽{⍵,⍨⊃(⍳1+≢⍵)~-⌿⍵[1 2 1∘.×⍳⌊2÷⍨≢⍵]}⍣⎕,⍬

Pruébalo en línea!


2

MATLAB, 156 147 bytes

Finalmente llegué a jugar golf un poco:

N=input('');s=[0;0];for n=1:N,x=s(n,~~s(n,:));try,a(n)=find(~ismember(1:max(x)+1,x),1);catch,a(n)=1;end,s(n+1:2*n-1,end+1)=2*a(n)-a(n-1:-1:1);end,a

Sin golf:

N=input('');                                   % read N from stdin

s=[0;0];
for n=1:N,
    x=s(n,~~s(n,:));                           % x=nonzeros(s(n,:));
    try,
        a(n)=find(~ismember(1:max(x)+1,x),1);  % smallest OK number
    catch,
        a(n)=1;                                % case of blank page for n
    end,

    s(n+1:2*n-1,end+1)=2*a(n)-a(n-1:-1:1);     % determined new forbidden values
end,
a                                              % print ans=...

La entrada se lee desde STDIN, y la impresión se realiza automáticamente con ans=y cosas adjuntas. Espero que esto califique como salida "razonable".

Esto también es una solución basada en tamiz: la variable s(i,:)mantiene un registro de los valores de secuencia que están prohibidas para a(i). El try-catchbloque es necesario para tratar el caso de una smatriz vacía (que significa cero completo) : en este caso, el valor más bajo de 1ya está permitido.

Sin embargo, la necesidad de memoria (¿o tiempo de ejecución?) Se vuelve bastante desordenada arriba N=2000. Así que aquí hay una solución no competitiva y más eficiente:

%pre-alloc
s = zeros([N,fix(N*0.07+20)]); %strict upper bound, needs adjusting later
i = zeros(1,N);

a = 1;
for n = 2:N,
    x = s(n,1:i(n));
    if isempty(x),
        a(n) = 1;
    else
        a(n) = find(~ismember(1:max(x)+1,x),1);
    end,

    j = n+1:min(2*n-1,N);
    i(j) = i(j)+1;
    s(N,max(i(j))) = 0;   %adjust matrix size if necessary
    b = a(n-1:-1:1);
    s(sub2ind([N,size(s,2)+1],j,i(j))) = 2*a(n)-b(1:length(j));
end

En esta implementación, la smatriz nuevamente contiene valores prohibidos, pero de manera ordenada, sin ningún bloque cero (que están presentes en la versión de la competencia). El vector índice irealiza un seguimiento de la cantidad de vectores prohibidos s. A primera vista, las celdas serían excelentes para realizar un seguimiento de la información almacenada s, pero serían lentas y no podríamos indexar un montón de ellas al mismo tiempo.

Una característica desagradable de MATLAB es que si bien puede decir M(1,end+1)=3;y expandir automáticamente una matriz, no puede hacer lo mismo con la indexación lineal. Tiene sentido (¿cómo debería MATLAB conocer el tamaño de matriz resultante, en cuyo marco debería interpretar los índices lineales?), Pero aún así me sorprendió. Esta es la razón de la línea superflua s(N,max(i(j))) = 0;: esto ampliará la smatriz para nosotros cuando sea necesario. La suposición de tamaño inicial N*0.07+20proviene de un ajuste lineal a los primeros elementos, por cierto.

Para probar el tiempo de ejecución, también verifiqué una versión ligeramente modificada del código, donde inicialicé la smatriz para que tuviera tamaño N/2. Para los primeros 1e5elementos, esto parece ser una suposición muy generosa, por lo que eliminé el paso de expansión smencionado en el párrafo anterior. Todo esto implica que el código será más rápido, pero también menos robusto a muy alto N(ya que no sé cómo se ve la serie allí).

Así que aquí hay algunos tiempos de ejecución, comparando

  • v1: la versión de golf competidora,
  • v2: la versión a prueba de tontos de bajo tamaño inicial y
  • v3: la versión generosa de tamaño inicial, podría fallar para N grande.

Medí esto en R2012b, tomando la mejor de 5 ejecuciones dentro de una definición de función con nombre tic/toc.

  1. N=100:
    • v1: 0.011342 s
    • v2: 0.015218 s
    • v3: 0.015076 s
  2. N=500:
    • v1: 0.101647 s
    • v2: 0.085277 s
    • v3: 0.081606 s
  3. N=1000:
    • v1: 0.641910 s
    • v2: 0.187911 s
    • v3: 0.183565 s
  4. N=2000:
    • v1: 5.010327 s
    • v2: 0.452892 s
    • v3: 0.430547 s
  5. N=5000:
    • v1: N / A (no esperó)
    • v2: 2.021213 s
    • v3: 1.572958 s
  6. N=10000:
    • v1: N / A
    • v2: 6.248483 s
    • v3: 5.812838 s

Parece que la v3versión es significativamente, pero no abrumadoramente más rápida. No sé si un elemento de incertidumbre (para muy grande N) vale el aumento menor en el tiempo de ejecución.


M=1;M(end+1)=2;funciona perfectamente bien para mi?
flawr

@flawr que funcionará para escalares y vectores. Intente en su M=rand(2); M(end+1)=2lugar :)
Andras Deak

Ah ahora veo =)
error

2

Jalea , 24 19 bytes

Esta es mi primera respuesta de Jelly en bastante tiempo. Contento de estar de vuelta.

Este es un puerto de mi respuesta APL que es una adaptación de muchos de los algoritmos utilizados aquí. La principal diferencia es que esto está indexado en 0.

Editar: -5 bytes gracias a Jonathan Allan.

Pruébalo en línea!

Ḋm2ɓṁḤ_
ŻJḟÇṂ;
1Ç¡U

Explicación

Ḋm2ɓṁḤ_  First link. Takes our current sequence S as our left argument.

         We are trying to calculate, of an arithmetic progression A B C, 
           the C using the formula, C = 2*B - A
Ḋ        Remove the first element of S.
 m2      Get every element at indices 0, 2, 4, ...
           This is equivalent to getting every second element of S, a list of As.
   ɓ     Starts a dyad with reversed arguments.
           The arguments here are S and As.
    ṁ    This molds S in the shape of As, giving us a list of Bs.
     Ḥ   We double the Bs.
      _  And subtract As from 2 * Bs.

ŻJḟÇṂ;  Second link. Takes S as our left argument.

Ż       Append a 0 to S.
 J      Range [1, len(z)]. This gets range [1, len(S) + 1].
  ḟÇ    Filter out the results of the previous link, our Cs.
    Ṃ   Take the minimum of Cs.
     ;  And concatenate it with the rest of the sequence so far.

1Ç¡U  Third link. Where we feed our input, n.

1     A list with the element 1.
 Ç¡   Run the previous link n times.
   U  Reverse everything at the end.

funcionará tan bien como œ-guardar un byte
Jonathan Allan

Bastante seguro de que puede poner a cero el índice (según la secuencia ) y reemplazarlo “”con la 1salida de una representación Jelly de una lista de un programa completo, ahorrando uno más.
Jonathan Allan

Œœị@2se puede jugar golf para Ḋm2salvar dos.
Jonathan Allan

L‘Rse puede jugar golf para ŻJsalvar uno.
Jonathan Allan

@JonathanAllan ¡Cinco bytes completos! ¡Gracias!
Sherlock9

1

ES6, 114 bytes

n=>[...r=Array(n)].map((x,i,s)=>{for(y=1;x&&x[y];y++);r[i]=y;for(j=i;++j<n;s[j][y+y-r[i+i-j]]=1)s[j]=s[j]||[]}&&r

Devuelve una matriz de los primeros n elementos de la secuencia, por lo que los índices están a 1 de la versión no reflejada a continuación. Usé el enfoque de tamiz. Esta versión se ralentiza después de aproximadamente n = 2000; una versión anterior evitaba leer el comienzo de la matriz, lo que significaba que no se ralentizaba hasta aproximadamente n = 2500. Una versión anterior utilizaba la matriz de tamices como una lista de valores prohibidos en lugar de una matriz booleana cuyos valores estaban prohibidos; esto podría llegar a aproximadamente n = 5000 sin romper el sudor. Mi versión original trató de usar máscaras de bits, pero resultó ser inútil (y también fue demasiado larga con 198 bytes).

La versión no tan lenta sin golfista:

function smoke(n) {
    result = [];
    sieve = [];
    for (i = 1; i <= n; i++) {
        value = 1;
        if (sieve[i]) {
            while (sieve[i][value]) {
                value++;
            }
        }
        result[i] = value;
        for (j = 1; j < i && i + j <= n; j++) {
            if (!sieve[i + j]) sieve[i + j] = [];
            sieve[i + j][value + value - result[i - j]] = true;
        }
    }
    return result;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.