分形烟雾序列


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作为输入,输出第一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
将头稍微向左移动,放大一点,然后就可以了!(:
瑕疵的

4
刚弹出一个发烧友的视频:youtube.com/watch?
v=o8c4uYnnNnc

2
我敢打赌,他的代码几乎不像高尔夫!
Luis Mendo

Answers:


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。生成一组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>02n-#<=--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中,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)]不是算术序列。

时间复杂度的上限(使用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),如果重要的话,p值<10 ^(-1291)。

在实现级别上,使用“ -O2”进行编译,大约需要35分钟才能计算出前20个值。


1
您的程序的时间复杂度是多少?
瑕疵的

@flawr在帖子中添加了一些时间复杂度分析
Michael Klein

3

Brachylog33 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字节:可以使用anda[s-o]a[s-2*o]a[s-=1]a[s-o]
GB

3

APL(Dyalog扩展),37 字节SBCS

非常感谢Adám在APL Orchard(一个学习APL语言的好地方)上写和打高尔夫球的答案的帮助。在线尝试!

编辑: -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的一个令人讨厌的功能是,尽管您可以说出M(1,end+1)=3;并自动扩展矩阵,但使用线性索引却无法做到这一点。这样做是有道理的(MATLAB应该如何知道最终的数组大小,并在此框架内解释线性索引?),但仍然让我感到惊讶。这就是多余线的原因s(N,max(i(j))) = 0;:这将s在需要时为我们扩展矩阵。起始尺寸猜测N*0.07+20顺便说一句,来自对前几个元素的线性拟合。

为了测试运行时,我还检查了代码的稍微修改后的版本,在其中将s矩阵初始化为具有size 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:不适用(没有等待)
    • 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适用于标量和向量。请尝试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整个五个字节!谢谢!
夏洛克

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.