フラクタル煙シーケンス


33

前書き

A229037には、非常に興味深いプロットがあります(少なくとも最初のいくつかの用語について)。

ある種のフラクタル特性を実際に持っているかもしれないという推測があります。

このシーケンスはどのように構築されますか?

a(1) = 1, a(2) = 1次に、各3項インデックスの算術3項シーケンスに対して、シーケンスの対​​応する値が算術シーケンスではないようにn>2、最小の正の整数を見つけるように定義します。a(n)n,n+k,n+2ka(n),a(n+k),a(n+2k)

チャレンジ

n入力として正の整数を指定すると、このシーケンスの最初のna(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

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追加しようとしている値を使用して、3要素の算術級数を形成する要素を見てみましょう。

? 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ます。aを回避するためにのセットを生成した後、コードは最小の補数を取得して出力し、リストに追加します。(実際には、計算は1ずつ減らされ、1だけ大きく印刷さrange(n)れて、候補のユニバースとして機能します。)


8

Mathematica、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の禁止値をチェックしないようにします。

やや読みやすいバージョンでは、結果をmaxfunction まで保存するこのコードから始め、fそれを上記の1行の純粋な関数に変換しました。

 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

ハスケル、908984、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)]が算術シーケンスではないことをチェックします。

時間の複雑さの上限(a(n)<=(n + 1)/ 2であるOEISページの事実を使用:

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)!)

't'の最初の1kの値を計算し、値のログで線形モデルを使用するとappxが得られたため、この境界がどれほど良いかわかりません。O(22 ^ n)、p値<10 ^(-1291)、それが重要な場合。

「-O2」でコンパイルする実装レベルでは、最初の20個の値を計算するのに約35分かかりました。


1
あなたのプログラムの時間の複雑さは何ですか?
フレイ

@flawrポストに時間の複雑さの分析を追加
Michael Klein

3

Brachylog33 31バイト

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

オンラインでお試しください!

重要な場合:このチャレンジに取り組んだ後に私が要求した機能のおかげで、2バイトのゴルフが可能になりました。

説明

シーケンスをリストとして逆順に繰り返し生成します。例えば [2,2,1,1,2,1,1]、最後に逆順にします。

ここにはいくつかのネストされた述語があります。それらを内側から見てみましょう。最初のものġh₃hᵐs₂ᶠ-ᵐ=は、候補サブシーケンスを取り、someの算術シーケンスである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]
GB

3

APL(Dyalog Extended)、37 バイトSBCS

APL言語を学ぶには絶好の場所であるThe APL Orchardでこの答えを書いてゴルフをしてくれたAdámに感謝します。オンラインでお試しください!

編集: Adámのおかげで-6バイト

⌽{⍵,⍨⊃(⍳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の厄介な機能の1つは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:なし
    • v2: 6.248483 s
    • v3: 5.812838 s

v3バージョンは大幅に向上しているように見えますが、圧倒的に高速ではありません。不確実性の要素(非常に大きい場合N)が実行時間をわずかに増やすだけの価値があるかどうかはわかりません。


M=1;M(end+1)=2;私にとって完璧に動作しますか?
-flawr

スカラーとベクトルに対して機能する@flawr。M=rand(2); M(end+1)=2代わりに試してください:)
アンドラスディーク

ああ今
==

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.

ちょうど同様に行いますœ-バイトの節約
ジョナサン・アラン

シーケンスごとに)インデックスをゼロにできるので、完全なプログラムからリストのJelly表現“”1出力し、もう1つ保存することで置き換えることができます。
ジョナサンアラン

Œœị@2Ḋm2節約するためにゴルフをするかもしれません。
ジョナサンアラン

L‘RŻJ節約するためにゴルフをするかもしれません。
ジョナサンアラン

@JonathanAllan 5つの全バイト!ありがとう!
Sherlock9

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個の要素の配列を返します。そのため、インデックスは、以下の変更されていないバージョンから1です。ふるいアプローチを使用しました。このバージョンは、約n = 2000の後に遅くなります。以前のバージョンでは、配列の先頭を読み取ることを避けていたため、約n = 2500までスローダウンしませんでした。古いバージョンでは、値が禁止されていたブール配列ではなく、禁止値のリストとしてSieve配列を使用していました。これは、汗をかくことなく約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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.