Послідовність фрактального диму


33

Вступ

A229037 має досить інтригуючий сюжет (принаймні, протягом перших кількох термінів):

Існує думка, що вона справді може мати якесь фрактальне властивість.

Як будується ця послідовність?

Визначити a(1) = 1, a(2) = 1то для кожного n>2знайти мінімальне натуральне число , a(n)таке , що для кожного арифметичного 3 члени послідовності n,n+k,n+2kіндексів, відповідні значення послідовності a(n),a(n+k),a(n+2k)є НЕ арифметичної послідовності.

Виклик

Враховуючи додатне ціле число nяк вихід, виведіть перші nчлени a(1), ... , a(n)цієї послідовності. (При будь-якому розумному форматуванні. Можливі провідні / навчальні символи / рядки не мають значення.)

Існують фрагменти для генерації цієї послідовності, але я думаю, що інші підходи можуть бути більш гольфними / більш підходящими для певних мов.

Будь ласка, повідомте нам, як працює ваша програма. Якщо ви перетинаєте особливо ефективний алгоритм, ви можете також згадати про це, оскільки це дозволить побудувати більше термінів послідовності за коротший час.

Перші кілька тестових випадків:

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

Більше тестів:

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

Усі терміни до n=100000них доступні тут: https://oeis.org/A229037/b229037.txt

Дякуємо @ MartinBüttner за допомогу та заохочення.


2
Гей, де я бачив цей графік раніше? :-D
Луїс Мендо

12
Зсуньте голову десь ліворуч, трохи збільшіть зображення, там ви йдете! (:
flawr

4
Щойно вискочило чисельне відео: youtube.com/watch?v=o8c4uYnnNnc
недолік

2
Б'юсь об заклад, його код не настільки голий!
Луїс Мендо

Відповіді:


12

Python 2, 95 байт

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

Основна хитрість полягає в генерації чисел, яких слід уникати новим значенням. Зберігаючи до цього часу зворотну послідовність l, давайте розглянемо, які елементи можуть формувати тричасну арифметичну прогресію зі значенням, яке ми збираємося додати.

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

Інші числа - це парні члени lта кожен другий елемент l, так zip(l,l[1::2]). Якщо ця пара , (b,c)то арифметична прогресія (a,b,c)відбувається з- за a=2*b-c. Після генерування набору as, щоб його уникнути, код бере мінімум доповнення, роздруковує його та додає до списку. (Насправді, обчислення проводяться з числами, зменшеними на 1, і надрукованими на 1 вище, щоб вони range(n)служили універсалом кандидатів.)


8

Математика, 95 байт

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

Звичайно, це не найкращий підхід, але це насправді досить ефективно, порівняно з алгоритмами, які я спробував зі сторінки OEIS.

На відміну від перевірки всіх заборонених значень для кожного s (n), коли ми потрапляємо туди, я використовую підхід на основі сит. Коли ми знаходимо нове значення s (n), ми відразу перевіряємо, які значення забороняє m> n . Тоді ми просто вирішуємо s (n + 1) , шукаючи перше значення, яке не було заборонено.

Це можна зробити ще ефективнішим, змінивши умовний --i>0на 2n-#<=--i>0. У цьому випадку ми уникаємо перевірки заборонених значень на n, більших за вхідні.

Для дещо більш читабельної версії я почав із цього коду, який зберігає результати maxу функції f, а потім перетворює його на вищевказану однорядкову чисту функцію:

 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 байт

Можливо, може бути більше гольфу, але це все ж гідна перша спроба:

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

Безголівки:

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

Це проста реалізація, яка повертає "0" поза межами. Потім для кожного можливого значення він перевіряє, що для всіх k <= n і в межах, [x, a (xk), a (x-2k)] не є арифметичною послідовністю.

Верхня межа часової складності (використовуючи факт на сторінці OEIS, що 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)!)

Я не впевнений, наскільки хороша ця межа, тому що обчислюючи перші 1k значення 't' та використовуючи лінійну модель на журналах значень, що даються appx. O (22 ^ n), з р-значенням <10 ^ (- 1291), якщо це має значення.

На рівні реалізації, компілюючи з '-O2', для розрахунку перших 20 значень знадобилося ~ 35 хв.


1
Яка часова складність вашої програми?
недолік

@flawr Додав до публікації аналіз складності в часі
Майкл Кляйн

3

Брахілог , 33 31 байт

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

Спробуйте в Інтернеті!

У випадку, якщо це має значення: 2-байтовий гольф став можливим завдяки функції, яку я просив, працюючи над цим викликом.

Пояснення

Ми ітераційно генеруємо послідовність у вигляді списку у зворотному порядку, наприклад [2,2,1,1,2,1,1], та повертаємо її в кінці.

Тут є пара вкладених предикатів. Давайте подивимось на них зсередини назовні. Перший ġh₃hᵐs₂ᶠ-ᵐ=, приймає подання кандидата a(n),a(n-1),...,a(0)і визначає, чи a(n),a(n-k),a(n-2k)є арифметична послідовність для деяких 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

Наприклад, із введенням [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.

Наступний предикат назовні, ~b.hℕ₁≜∧.¬{...}∧вводить підряд a(n-1),a(n-2),...,a(0)і виводить наступний більший підряд 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

Нарешті, головний предикат ;Ė{...}ⁱ⁽↔приймає вхідне число і виводить, що багато членів послідовності.

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

Рубін , 71 байт

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

Спробуйте в Інтернеті!

Генерує всі заборонені значення, потім приймає доповнення цього масиву в (1..n) і приймає перше значення результату. Це означає, що я припускаю, що a[n] <= nдля всіх n, що легко довести за допомогою індукції (якщо перші n / 2 доданки всі менше n / 2, то не може бути арифметичної прогресії, що веде до n).

Синтаксичний трюк тут також м'яко цікавий: *aвикористовується для ініціалізації масиву додаткових аргументів (який би ігнорувався, якщо ми передали його), а потім a.fillмутує масив аргументів і імпліцитно повертає його.


1
-1 байт: замість a[s-o]і a[s-2*o], ви можете використовувати a[s-=1]іa[s-o]
ГБ

3

APL (Dyalog Extended) , 37 байт SBCS

Величезне спасибі Адаму за його допомогу в написанні та гольф на цю відповідь у Фруктовому саду APL - прекрасне місце для вивчення мови APL Спробуйте в Інтернеті!

Редагувати: -6 байт завдяки Adám

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

Пояснення

{⍵,⍨⊃(⍳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 байт SBCS

Ось швидше, але менш гофроване рішення, яке можна розрахувати ⍺(10000)за кілька секунд.

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

Спробуйте в Інтернеті!


2

MATLAB, 156 147 байт

Нарешті я трохи погукав:

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

Безголівки:

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

Введення зчитується з STDIN, а друк проводиться автоматично з ans=додаванням матеріалів. Я сподіваюся, що це кваліфікується як "розумний" результат.

Це також сита на основі розчину: змінна s(i,:)відстежує тих значень послідовності , які заборонені для a(i). try-catchБлок необхідний для лікування випадок порожній ( що означає повний нуль) sматриці: в цьому випадку найменше значення 1вже дозволено.

Однак потреба в пам’яті (або час роботи?) Стає вище безладним N=2000. Тож ось неконкурентне, більш ефективне рішення:

%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

У цій реалізації sматриця знову містить заборонені значення, але в упорядкованому порядку, без будь-яких нульових блоків (які присутні у конкуруючій версії). Індексний вектор iвідстежує кількість заборонених векторів у s. На перший погляд осередки було б чудово відслідковувати інформацію, що зберігається s, але це буде повільно, і ми не могли одночасно проіндексувати купу їх.

Одна неприємна особливість MATLAB полягає в тому, що, хоча ви можете сказати M(1,end+1)=3;і автоматично розширити матрицю, ви не можете зробити те ж саме з лінійною індексуванням. Це має сенс (як MATLAB повинен знати розмір отриманого масиву, в рамках якого він повинен інтерпретувати лінійні індекси?), Але це все одно мене здивувало. Це причина зайвої лінії s(N,max(i(j))) = 0;: це дозволить нам розширити sматрицю, коли це буде необхідно. До N*0.07+20речі, вихідний розмір походить від лінійного прилягання до перших кількох елементів, до речі.

Для того щоб перевірити час виконання, я також перевірив трохи змінену версію коду, де я ініціалізував sматрицю, щоб вона мала розмір N/2. Для перших 1e5елементів це здається дуже щедрим здогадком, тому я видалив етап розширення, sзгаданий у попередньому пункті. Вони разом означають, що код буде швидшим, але й менш надійним на дуже високому рівні N(оскільки я не знаю, як виглядає серія там).

Отож, кілька порівняльних моментів

  • v1: конкуруюча версія для гольфу,
  • v2: версія з низьким рівнем старту, дуростійка версія та
  • v3: версія великого стартового розміру, можливо, не вдасться до великих N версій.

Я виміряв їх на R2012b, взявши найкращі з 5 прогонів всередині названого визначення функції 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 (не чекав)
    • v2: 2.021213 s
    • v3: 1.572958 s
  6. N=10000:
    • v1: N / A
    • v2: 6.248483 s
    • v3: 5.812838 s

Здавалося б, v3версія значно, але не надзвичайно швидша. Я не знаю, чи варто елемент невпевненості (для дуже великих N) незначного збільшення часу виконання.


M=1;M(end+1)=2;працює для мене ідеально добре?
невдача

@flawr, який працюватиме за скалярів та векторів. Спробуйте M=rand(2); M(end+1)=2замість цього :)
Andras Deak

Ах тепер я бачу =)
недолік

2

Желе , 24 19 байт

Це моя перша відповідь желе за досить довгий час. Радий, що повернувся.

Це порт моєї відповіді APL, який сам по собі є адаптацією багатьох використовуваних тут алгоритмів. Основна відмінність полягає в тому, що це 0-індексується.

Редагувати: -5 байт завдяки Джонатану Аллану.

Спробуйте в Інтернеті!

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

Пояснення

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

зробить так само добре, як œ-зберегти байт
Джонатан Аллан

Упевнений , ви можете обнулити індекс (як в послідовності ) і таким чином замінити “”з 1висновком уявлення Jelly списку з повної програми, економлячи ще один.
Джонатан Аллан

Œœị@2може бути гольф, щоб Ḋm2заощадити двох.
Джонатан Аллан

L‘Rможе бути гольф, щоб ŻJврятувати одного.
Джонатан Аллан

@JonathanAllan П'ять цілих байтів! Спасибі!
Шерлок9

1

ES6, 114 байт

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

Повертає масив перших n елементів послідовності, тож індекси відхилені від версії, що не перебуває внизу, нижче. Я використовував ситовий підхід. Ця версія сповільнюється приблизно через n = 2000; попередня версія уникала зчитування початку масиву, що означало, що він не сповільнився до приблизно n = 2500. Старіша версія використовувала ситовий масив як список заборонених значень, а не булівський масив, значення яких було заборонено; це може досягти приблизно n = 5000, не порушуючи поту. У моїй оригінальній версії спробували використовувати бітові маски, але це виявилося непосильним (а також було занадто довгим у 198 байт).

Не зовсім така повільна версія безготівки:

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.