Urutan Asap Fraktal

33

pengantar

A229037 memiliki plot yang cukup menarik (setidaknya untuk beberapa istilah pertama):

Ada dugaan, bahwa memang mungkin memiliki semacam properti fraktal.

Bagaimana urutan ini dibangun?

Tentukan a(1) = 1, a(2) = 1maka untuk setiap n>2menemukan positif minimal bilangan bulat a(n)sehingga untuk setiap urutan 3 jangka aritmatika n,n+k,n+2kindeks, nilai-nilai yang sesuai urutan a(n),a(n+k),a(n+2k)adalah tidak urutan aritmatika.

Tantangan

Diberikan bilangan bulat positif nsebagai input, output nistilah pertama a(1), ... , a(n)dari urutan ini. (Dengan pemformatan yang masuk akal. Karakter / string terkemuka / pelatihan tidak relevan.)

Ada cuplikan untuk membuat urutan ini, tetapi saya pikir pendekatan lain mungkin lebih cocok untuk golf / lebih cocok untuk bahasa tertentu.

Beri tahu kami cara kerja program Anda. Jika Anda menemukan suatu persilangan suatu algoritma yang sangat efisien, Anda mungkin ingin menyebutkannya juga, karena akan memungkinkan untuk memplot lebih banyak istilah dari urutan dalam waktu yang lebih singkat.

Beberapa kasus uji pertama:

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

Lebih banyak testcases:

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

Semua persyaratan hingga n=100000tersedia di sini: https://oeis.org/A229037/b229037.txt

Terima kasih @ MartinBüttner atas bantuan dan dorongannya.

cacat
sumber
2
Hei, di mana saya pernah melihat grafik ini sebelumnya? :-D
Luis Mendo
12
Geser kepala Anda agak ke kiri, perbesar sedikit, ini dia! (:
flawr
4
Video numberphile baru saja muncul: youtube.com/watch?v=o8c4uYnnNnc
flawr
2
Saya yakin kodenya hampir tidak seperti golf!
Luis Mendo

Jawaban:

12

Python 2, 95 byte

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

Trik utamanya adalah dalam menghasilkan angka-angka yang harus dihindari oleh nilai baru. Menjaga urutan terbalik sejauh ini l, mari kita lihat elemen apa yang mungkin membentuk perkembangan aritmatika tiga istilah dengan nilai yang akan kita tambahkan.

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

Angka-angka lainnya adalah anggota berpasangan ldan setiap elemen kedua l, jadi zip(l,l[1::2]). Jika pasangan ini (b,c)maka perkembangan aritmatika (a,b,c)terjadi untuk a=2*b-c. Setelah membuat set auntuk menghindari, kode mengambil minimum dari komplemen, mencetaknya, dan menambahkannya ke daftar. (Sebenarnya, perhitungan dilakukan dengan angka yang berkurang 1, dan dicetak 1 lebih tinggi, untuk range(n)dijadikan sebagai calon dari seluruh dunia.)

Tidak
sumber
8

Mathematica, 95 byte

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

Tentu saja bukan pendekatan golf, tetapi ini sebenarnya cukup efisien, dibandingkan dengan algoritma yang saya coba dari halaman OEIS.

Berbeda dengan memeriksa semua nilai terlarang untuk setiap s (n) ketika kami sampai di sana saya menggunakan pendekatan berbasis saringan. Ketika kami menemukan nilai baru s (n), kami segera memeriksa nilai mana yang melarang ini untuk m> n . Kemudian kita hanya menyelesaikan s (n +1) dengan mencari nilai pertama yang tidak dilarang.

Ini dapat dibuat lebih efisien dengan mengubah persyaratan --i>0menjadi 2n-#<=--i>0. Dalam hal ini, kami menghindari memeriksa nilai terlarang untuk n lebih besar dari input.

Untuk versi yang lebih mudah dibaca, saya mulai dengan kode ini, yang menyimpan hasil hingga maxdalam suatu fungsi f, dan kemudian memutarnya ke fungsi murni satu-baris di atas:

 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;
  ]
Martin Ender
sumber
3

Haskell, 90 , 89 , 84 , 83 byte

Mungkin bisa bermain golf lebih banyak, tetapi ini masih merupakan upaya pertama yang layak :

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

Tidak Disatukan:

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

Ini adalah implementasi sederhana yang mengembalikan '0' untuk di luar batas. Kemudian, untuk setiap nilai yang mungkin, ia memeriksa bahwa untuk semua k <= n dan dalam batas, [x, a (xk), a (x-2k)] bukan urutan aritmatika.

Kompleksitas waktu terikat atas (menggunakan fakta dari halaman OEIS bahwa 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)!)

Saya tidak yakin seberapa bagus ikatan ini karena menghitung nilai 1k pertama 't' dan menggunakan model linier pada log dari nilai yang diberikan appx. O (22 ^ n), dengan p-value <10 ^ (- 1291), jika itu penting.

Pada tingkat implementasi, kompilasi dengan '-O2', butuh ~ 35 menit untuk menghitung 20 nilai pertama.

Michael Klein
sumber
1
Apa kompleksitas waktu untuk program Anda?
flawr
@ flawr Menambahkan beberapa analisis kompleksitas waktu ke pos
Michael Klein
3

Brachylog , 33 31 byte

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

Cobalah online!

Dalam hal itu penting: Golf 2-byte dimungkinkan berkat fitur yang saya minta setelah mengerjakan tantangan ini.

Penjelasan

Kami menghasilkan urutan berulang sebagai daftar dalam urutan terbalik, misalnya [2,2,1,1,2,1,1], dan membalikkannya di akhir.

Ada beberapa predikat bersarang di sini. Mari kita lihat mereka dari dalam ke luar. Yang pertama ġh₃hᵐs₂ᶠ-ᵐ=,, mengambil kandidat berikutnya a(n),a(n-1),...,a(0)dan menentukan apakah a(n),a(n-k),a(n-2k)urutan aritmatika untuk beberapak .

ġ            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

Misalnya dengan masukan dari [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.

Predikat berikutnya ke luar,, ~b.hℕ₁≜∧.¬{...}∧memasukkan a(n-1),a(n-2),...,a(0)urutan dan output urutan berikutnya yang lebih besar 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

Terakhir, predikat utama ;Ė{...}ⁱ⁽↔mengambil nomor input dan output yang banyak termsinya.

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

Ruby , 71 byte

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

Cobalah online!

Menghasilkan semua nilai terlarang, kemudian mengambil pelengkap array itu di (1..n) dan mengambil nilai pertama dari hasilnya. Itu berarti saya menganggap itua[n] <= n untuk semua n, yang mudah dibuktikan menggunakan induksi (jika n / 2 istilah pertama semuanya kurang dari n / 2, maka tidak mungkin ada perkembangan aritmatika yang mengarah ke n).

Trik sintaksis di sini juga agak menarik: *adigunakan untuk menginisialisasi array argumen tambahan (yang akan diabaikan jika kita melewatkannya), dan kemudian a.fillmengubah array argumen dan secara implisit mengembalikannya.

histokrat
sumber
1
-1 byte: alih-alih a[s-o]dan a[s-2*o], Anda dapat menggunakan a[s-=1]dana[s-o]
GB
3

APL (Dyalog Extended) , 37 byte SBCS

Terima kasih banyak kepada Adám atas bantuannya dalam menulis dan bermain golf jawaban ini di The APL Orchard , tempat yang bagus untuk belajar bahasa APL. Cobalah online!

Edit: -6 byte terima kasih kepada Adám

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

Penjelasan

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

Berikut ini adalah solusi yang lebih cepat tetapi kurang golf yang dapat dihitung ⍺(10000)dalam beberapa detik.

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

Cobalah online!

Sherlock9
sumber
2

MATLAB, 156 147 byte

Saya akhirnya bisa bermain golf ini sedikit:

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

Tidak Disatukan:

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

Input dibaca dari STDIN, dan pencetakan dilakukan secara otomatis dengan ans= dan barang ditambahkan. Saya berharap ini memenuhi syarat sebagai output "masuk akal".

Ini juga merupakan solusi berbasis saringan: variabel s(i,:)terus melacak dari nilai-nilai urut yang dilarang untuk a(i). The try-catchblok diperlukan untuk mengobati kasus kosong (berarti nol penuh) smatriks: dalam hal ini nilai terendah1 sudah diperbolehkan.

Namun, kebutuhan memori (atau runtime?) Menjadi sangat berantakan di atas N=2000. Jadi, inilah solusi yang tidak bersaing dan lebih efisien:

%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

Dalam implementasi ini, smatriks kembali berisi nilai-nilai terlarang, tetapi dengan cara yang tertata dengan baik, tanpa nol blok (yang ada dalam versi yang bersaing). Vektor indeks imelacak jumlah vektor terlarang di s. Pada awalnya sel akan bagus untuk melacak informasi yang disimpan s, tetapi itu akan lambat, dan kami tidak dapat mengindeks banyak dari mereka pada saat yang sama.

Salah satu fitur buruk MATLAB adalah walaupun Anda dapat mengatakan M(1,end+1)=3;dan secara otomatis memperluas matriks, Anda tidak dapat melakukan hal yang sama dengan pengindeksan linear. Agak masuk akal (bagaimana MATLAB harus tahu ukuran array yang dihasilkan, dalam kerangka yang seharusnya menafsirkan indeks linier?), Tetapi masih mengejutkan saya. Ini adalah alasan untuk baris berlebihan s(N,max(i(j))) = 0;: ini akan memperluas smatriks untuk kita kapan pun diperlukan. Tebakan ukuran awalN*0.07+20 berasal dari kecocokan linear dengan beberapa elemen pertama.

Untuk menguji runtime, saya juga memeriksa versi kode yang sedikit dimodifikasi, di mana saya menginisialisasi smatriks untuk memiliki ukuran N/2. Untuk 1e5elemen pertama ini tampaknya merupakan perkiraan yang sangat murah hati, jadi saya menghapus langkah ekspansi yang sdisebutkan dalam paragraf sebelumnya. Ini bersama-sama menyiratkan bahwa kode akan lebih cepat, tetapi juga kurang kuat di sangat tinggi N(karena saya tidak tahu bagaimana seri ini terlihat di sana).

Jadi, inilah beberapa runtime, membandingkan

  • v1: versi golf yang bersaing,
  • v2: versi awal-ukuran rendah, bukti-bodoh dan
  • v3: versi ukuran mulai yang murah hati, mungkin-gagal-untuk-besar-N.

Saya mengukur ini pada R2012b, mengambil yang terbaik dari 5 berjalan di dalam definisi fungsi bernama dengan 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: T / A (tidak menunggu)
    • v2: 2.021213 s
    • v3: 1.572958 s
  6. N=10000:
    • v1: T / A
    • v2: 6.248483 s
    • v3: 5.812838 s

Tampaknya v3versi ini signifikan, tetapi tidak terlalu cepat. Saya tidak tahu apakah elemen ketidakpastian (untuk sangat besar N) bernilai peningkatan minor dalam runtime.

Andras Deak
sumber
M=1;M(end+1)=2;berfungsi dengan baik untuk saya?
flawr
@ flawr yang berfungsi untuk skalar dan vektor. Coba M=rand(2); M(end+1)=2saja :)
Andras Deak
Ah sekarang saya mengerti =)
flawr
2

Jelly , 24 19 byte

Ini adalah jawaban Jelly pertamaku dalam beberapa saat. Senang bisa kembali.

Ini adalah port jawaban APL saya yang merupakan adaptasi dari banyak algoritma yang digunakan di sini. Perbedaan utama adalah ini diindeks 0.

Sunting: -5 byte terima kasih kepada Jonathan Allan.

Cobalah online!

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

Penjelasan

Ḋ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.
Sherlock9
sumber
akan melakukan serta œ-menghemat byte
Jonathan Allan
Cukup yakin Anda bisa nol indeks (sesuai urutan ) dan ganti “”dengan 1menampilkan representasi Jelly daftar dari program penuh, menyimpan satu lagi.
Jonathan Allan
Œœị@2dapat bermain golf untuk Ḋm2menghemat dua.
Jonathan Allan
L‘Rmungkin golf untuk ŻJmenyimpannya.
Jonathan Allan
@ JonathanAllan Lima byte penuh! Terima kasih!
Sherlock9
1

ES6, 114 byte

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

Mengembalikan larik elemen n pertama dari urutan, sehingga indeksnya adalah 1 dari versi tanpa tanda di bawah ini. Saya menggunakan pendekatan saringan. Versi ini melambat setelah sekitar n = 2000; versi sebelumnya menghindari pembacaan awal array yang berarti tidak memperlambat sampai sekitar n = 2500. Versi yang lebih lama menggunakan array saringan sebagai daftar nilai terlarang daripada array boolean yang nilai-nilainya dilarang; ini bisa mencapai n = 5000 tanpa berkeringat. Versi asli saya mencoba menggunakan bitmask tetapi ternyata tidak membantu (dan juga terlalu panjang pada 198 byte).

Versi yang tidak terlalu lambat 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;
}
Neil
sumber