Fraktale Rauchfolge


32

Einführung

A229037 hat eine ziemlich interessante Handlung (zumindest für die ersten Begriffe):

Es gibt die Vermutung, dass es tatsächlich eine Art fraktale Eigenschaft haben könnte.

Wie ist diese Sequenz aufgebaut?

Definieren a(1) = 1, a(2) = 1dann für jedes n>2eine minimale positive ganze Zahl finden , a(n)so dass für jede arithmetische 3 Begriff Sequenz n,n+k,n+2kvon Indizes, die entsprechenden Werte der Sequenz a(n),a(n+k),a(n+2k)ist nicht eine arithmetische Sequenz.

Herausforderung

Geben Sie bei einer positiven Ganzzahl nals Eingabe die ersten nTerme a(1), ... , a(n)dieser Sequenz aus. (Bei angemessener Formatierung. Mögliche führende / trainierende Zeichen / Zeichenfolgen sind irrelevant.)

Es gibt Schnipsel zum Erzeugen dieser Sequenz, aber ich denke, dass andere Ansätze für bestimmte Sprachen besser geeignet sind.

Bitte teilen Sie uns mit, wie Ihr Programm funktioniert. Wenn Sie auf einen besonders effizienten Algorithmus stoßen, sollten Sie dies ebenfalls erwähnen, da dadurch mehr Terme der Sequenz in kürzerer Zeit aufgezeichnet werden können.

Erste Testfälle:

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

Weitere Testfälle:

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

Alle Bedingungen bis n=100000sind hier verfügbar: https://oeis.org/A229037/b229037.txt

Danke @ MartinBüttner für die Hilfe und Ermutigung.


2
Hey, wo habe ich diese Grafik schon gesehen? :-D
Luis Mendo

12
Bewegen Sie Ihren Kopf etwas nach links, zoomen Sie ein wenig hinein, los geht's! (:
Fehler

4
Ein Numberphile-Video ist gerade aufgetaucht: youtube.com/watch?v=o8c4uYnnNnc
flawr

2
Ich wette, sein Code ist bei weitem nicht so golfen!
Luis Mendo

Antworten:


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

Der Haupttrick besteht darin, die Zahlen zu generieren, die der neue Wert vermeiden muss. Behalten lwir die bisherige umgekehrte Reihenfolge bei und schauen wir uns an, welche Elemente mit dem Wert, den wir hinzufügen möchten, eine arithmetische Dreierfolge bilden könnten.

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

Die anderen Zahlen sind die gepaarten Mitglieder lund jedes zweite Element von l, so zip(l,l[1::2]). Wenn dieses Paar ist, passiert (b,c)die arithmetische Folge (a,b,c)für a=2*b-c. Nach dem Generieren der azu vermeidenden Menge von 's nimmt der Code das Minimum des Komplements, druckt es aus und stellt es der Liste voran. (Tatsächlich wird die Berechnung mit Zahlen durchgeführt, die um 1 verringert und um 1 höher gedruckt wurden, damit range(n)sie als Universum von Kandidaten dienen können.)


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

Mit Sicherheit nicht der golferischste Ansatz, aber im Vergleich zu den Algorithmen, die ich auf der OEIS-Seite ausprobiert habe, ist dies tatsächlich ziemlich effizient.

Im Gegensatz zur Überprüfung aller verbotenen Werte für jedes s (n), wenn wir dort ankommen, benutze ich einen siebbasierten Ansatz. Wenn wir einen neuen Wert s (n) finden , überprüfen wir sofort, welche Werte dies für m> n verbietet . Dann lösen wir einfach die s (n + 1), indem nach dem ersten Wert suchen, der nicht verboten war.

Dies kann durch Ändern der Bedingung --i>0auf noch effizienter gestaltet werden 2n-#<=--i>0. In diesem Fall vermeiden wir es, verbotene Werte auf zu überprüfen n zu größer als die Eingabe sind.

Für eine etwas besser lesbare Version habe ich mit diesem Code begonnen, in dem die Ergebnisse maxin einer Funktion fgespeichert sind, und dann die obige einzeilige reine Funktion verwendet:

 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

Kann wahrscheinlich mehr golfen werden, aber dies ist immer noch ein anständiger erster Versuch:

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

Ungolfed:

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

Dies ist eine einfache Implementierung, die '0' für außerhalb der Grenzen zurückgibt. Dann wird für jeden möglichen Wert geprüft, ob für alle k <= n und in Grenzen [x, a (xk), a (x-2k)] keine arithmetische Folge ist.

Obergrenze für Zeitkomplexität (unter Verwendung der Tatsache von der OEIS-Seite, dass 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)!)

Ich bin nicht sicher, wie gut diese Schranke ist, weil die Berechnung der ersten 1k-Werte von 't' und die Verwendung eines linearen Modells in den Protokollen der Werte appx ergab. O (22 ^ n), mit p-Wert <10 ^ (- 1291), falls es darauf ankommt.

Auf Implementierungsebene dauerte das Kompilieren mit '-O2' ~ 35 Minuten, um die ersten 20 Werte zu berechnen.


1
Was ist die zeitliche Komplexität für Ihr Programm?
Fehler

@flawr Zeitliche Komplexitätsanalyse zum Beitrag hinzugefügt
Michael Klein

3

Brachylog , 33 31 Bytes

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

Probieren Sie es online!

Für den Fall, dass es darauf ankommt: Das 2-Byte-Golfen war dank einer von mir gewünschten Funktion möglich nach der Arbeit an dieser Herausforderung .

Erläuterung

Wir generieren die Sequenz iterativ als Liste in umgekehrter Reihenfolge, z [2,2,1,1,2,1,1] und kehren sie am Ende um.

Hier gibt es ein paar verschachtelte Prädikate. Schauen wir sie uns von innen nach außen an. Die erste ġh₃hᵐs₂ᶠ-ᵐ=nimmt eine Kandidatensubsequenz a(n),a(n-1),...,a(0)und bestimmt, ob a(n),a(n-k),a(n-2k)es sich bei einigen um eine arithmetische Sequenz handelt 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

Zum Beispiel mit Eingabe von [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.

Das nächste Prädikat nach außen gibt ~b.hℕ₁≜∧.¬{...}∧eine Teilfolge ein a(n-1),a(n-2),...,a(0)und gibt die nächstgrößere Teilfolge aus 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

Schließlich nimmt das Hauptprädikat ;Ė{...}ⁱ⁽↔eine Eingabenummer und gibt so viele Terme der Sequenz aus.

;Ė{...}ⁱ⁽↔
;           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]}}

Probieren Sie es online!

Erzeugt alle verbotenen Werte, nimmt dann das Komplement dieses Arrays in (1..n) und nimmt den ersten Wert des Ergebnisses. Das heißt, ich gehe davon aus, dass a[n] <= nfür alle n, was durch Induktion leicht bewiesen werden kann (wenn die ersten n / 2 Terme alle kleiner als n / 2 sind, kann es keine arithmetische Progression geben, die zu n führt).

Der syntaktische Trick ist auch hier ein wenig interessant: Er *awird verwendet, um ein Array zusätzlicher Argumente zu initialisieren (die ignoriert würden, wenn wir eines übergeben würden), und dann a.filldas Argumentarray zu mutieren und implizit zurückzugeben.


-1 Byte: Anstelle von a[s-o]und a[s-2*o]können Sie vor a[s-=1]a[s-o]
GB verwenden

3

APL (Dyalog Extended) , 37 Byte SBCS

Vielen Dank an Adám für seine Hilfe beim Schreiben und Golfen dieser Antwort in The APL Orchard , einem großartigen Ort, um die APL-Sprache zu lernen. Probieren Sie es online!

Edit: -6 Bytes dank Adám

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

Erläuterung

{⍵,⍨⊃(⍳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 Byte SBCS

Hier ist eine schnellere, aber weniger golferische Lösung, die ⍺(10000)in wenigen Sekunden berechnet werden kann .

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

Probieren Sie es online!


2

MATLAB, 156 147 Bytes

Ich habe es endlich geschafft, ein bisschen zu golfen:

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

Ungolfed:

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=...

Die Eingabe wird aus STDIN gelesen und der Ausdruck erfolgt automatisch mit ans=angehängten Daten . Ich hoffe das qualifiziert sich als "vernünftige" Ausgabe.

Dies ist auch eine siebbasierte Lösung: die Variable s(i,:) verfolgt die Sequenzwerte, die für verboten sinda(i) . Der try-catchBlock wird benötigt, um den Fall einer leeren (dh vollen Null) sMatrix zu behandeln. In diesem Fall ist der niedrigste Wert von 1bereits zulässig.

Jedoch wird der Speicherbedarf (oder die Laufzeit?) Oben ziemlich unordentlich N=2000. Hier ist eine nicht konkurrierende, effizientere Lösung:

%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

In dieser Implementierung wird die s enthält Matrix wiederum verbotene Werte, jedoch auf eine geordnete Weise, ohne Nullblöcke (die in der Konkurrenzversion vorhanden sind). Der Indexvektor iverfolgt die Anzahl der verbotenen Vektoren in s. Auf den ersten Blick wären Zellen großartig, um den Überblick über die darin gespeicherten Informationen zu behalten s, aber diese wären langsam, und wir könnten nicht einen Haufen von ihnen gleichzeitig indizieren.

Eine unangenehme Eigenschaft von MATLAB ist, dass, während Sie sagen können M(1,end+1)=3; eine Matrix und automatisch erweitern können, mit der linearen Indizierung jedoch nicht dasselbe tun können. Es ist irgendwie sinnvoll (wie sollte MATLAB die resultierende Array-Größe kennen, in deren Rahmen es die linearen Indizes interpretieren sollte?), Aber es hat mich trotzdem überrascht. Dies ist der Grund für die überflüssige Zeile s(N,max(i(j))) = 0;: Dies erweitert die sMatrix für uns, wann immer dies erforderlich ist. Die Startgröße erratenN*0.07+20 ergibt sich übrigens aus einer linearen Anpassung an die ersten paar Elemente.

Um die Laufzeit zu testen, habe ich auch eine leicht geänderte Version des Codes überprüft, in der ich die sMatrix mit der Größe initialisiert habeN/2 . Für die ersten 1e5Elemente scheint dies eine sehr großzügige Vermutung zu sein, daher habe ich den sim vorherigen Absatz erwähnten Erweiterungsschritt entfernt . Zusammengenommen bedeutet dies, dass der Code schneller ist, bei sehr hohen Werten jedoch auch weniger robustN (da ich nicht weiß, wie die Serie dort aussieht).

Also hier sind ein paar Laufzeiten im Vergleich

  • v1: die konkurrierende Golfversion,
  • v2: die niedrig startende, narrensichere Version und
  • v3: die großzügige Startgröße, die möglicherweise nicht für große N-Versionen geeignet ist.

Ich habe diese auf R2012b gemessen und dabei das Beste aus 5 Läufen in einer benannten Funktionsdefinition mit genommen 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 (hat nicht gewartet)
    • v2: 2.021213 s
    • v3: 1.572958 s
  6. N=10000:
    • v1: N / A
    • v2: 6.248483 s
    • v3: 5.812838 s

Es scheint, dass die v3Version bedeutend, aber nicht überwältigend schneller ist. Ich weiß nicht, ob ein Element der Unsicherheit (für sehr große N) die geringfügige Erhöhung der Laufzeit wert ist.


M=1;M(end+1)=2;Funktioniert das bei mir einwandfrei?
Fehler

@flawr, das für Skalare und Vektoren funktioniert. Versuchen Sie es M=rand(2); M(end+1)=2stattdessen :)
Andras Deak

Ah, jetzt
verstehe

2

Gelee , 24 19 Bytes

Dies ist meine erste Gelee-Antwort seit einiger Zeit. Ich bin froh, zurück zu sein.

Dies ist ein Port meiner APL-Antwort, die selbst eine Anpassung vieler der hier verwendeten Algorithmen ist. Der Hauptunterschied besteht darin, dass dies 0-indiziert ist.

Edit: -5 Bytes dank Jonathan Allan.

Probieren Sie es online!

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

Erläuterung

Ḋ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.

Genauso gut wie das œ-Speichern eines Bytes
Jonathan Allan

Ziemlich sicher , können Sie Index (nach Null - Sequenz ) und so ersetzen “”mit 1einer Jelly Darstellung einer Liste von einem Vollprogramm ausgibt, spart man mehr.
Jonathan Allan

Œœị@2kann zum Ḋm2sparen von zwei golfen werden .
Jonathan Allan

L‘Rkann man zum ŻJsparen golfen .
Jonathan Allan

@ JonathanAllan Fünf ganze Bytes! Vielen Dank!
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

Gibt ein Array der ersten n Elemente der Sequenz zurück, sodass die Indizes 1 von der ungolfed-Version unten abweichen. Ich habe den Siebansatz verwendet. Diese Version verlangsamt sich nach etwa n = 2000; Eine frühere Version vermied es, den Anfang des Arrays abzulesen, was bedeutete, dass es nicht langsamer wurde, bis etwa n = 2500. In einer älteren Version wurde das Sieb-Array als Liste verbotener Werte verwendet und nicht als boolesches Array, dessen Werte verboten waren. dies könnte zu ungefähr n = 5000 kommen, ohne Schweiß zu brechen. Meine ursprüngliche Version versuchte, Bitmasken zu verwenden, aber das erwies sich als nicht hilfreich (und war mit 198 Bytes auch viel zu lang).

Die nicht ganz so langsame Version ungolfed:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.