最短加法链


23

加法链是从1开始的整数序列,其中除初始1之外的每个整数都是两个先前整数的总和。

例如,这是一个附加链:

[1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

这是使它成为加法链的总和:

1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
3 + 4 = 7
1 + 7 = 8
8 + 8 = 16
16 + 16 = 32
7 + 32 = 39
32 + 39 = 71

在此挑战中,您将获得一个正整数n,并且必须输出以结尾的最短加法链之一n

示例-请注意,有许多可能的输出,您需要查找的只是一条短的加法链:

1: [1]
2: [1, 2]
3: [1, 2, 3]
4: [1, 2, 4]
5: [1, 2, 3, 5]
6: [1, 2, 3, 6]
7: [1, 2, 3, 4, 7]
11: [1, 2, 3, 4, 7, 11]
15: [1, 2, 3, 5, 10, 15]
19: [1, 2, 3, 4, 8, 11, 19]
29: [1, 2, 3, 4, 7, 11, 18, 29]
47: [1, 2, 3, 4, 7, 10, 20, 27, 47]
71: [1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

标准I / O规则等。禁止使用标准漏洞。高尔夫代码:最少字节获胜。




1
是否允许以相反的顺序输出链条?
Arnauld

@Arnauld不,这个特定的命令。
isaacg

Answers:


6

Haskell,57个字节

c=[1]:[x++[a+b]|x<-c,a<-x,b<-x]
f n=[x|x<-c,last x==n]!!0

蛮力解决方案。 在线尝试!

说明

无限列表c包含所有加法链,按长度排序。通过x从中获取一个列表c和中的两个元素x,并将其总和追加到,就其本身进行归纳定义x。该函数f查找c以所需数字​​结尾的第一个列表。

c=            -- c is the list of lists
 [1]:         -- containing [1] and
 [x           -- each list x
  ++[a+b]     -- extended with a+b
 |x<-c,       -- where x is drawn from c,
  a<-x,       -- a is drawn from x and
  b<-x]       -- b is drawn from x.
f n=          -- f on input n is:
 [x           -- take list of those lists x
 |x<-c,       -- where x is drawn from c and
  last x==n]  -- x ends with n,
 !!0          -- return its first element.

4

Brachylog,14个字节

∧≜;1{j⊇Ċ+}ᵃ⁽?∋

在线尝试!

蛮力提交使用迭代加深构建所有可能的加法链,并在找到包含其正确参数的链时停止。与大多数Brachylog提交不同,这是一个函数提交,它通过其右自变量输入(通常称为“输出”),并通过其左自变量输出(通常称为“输入”);这样做有点争议,但是对这个问题的最高评价的元答案说是合法的(并且这样做与我们正常的函数I / O默认值一致)。如果我们以更常规的方式使用输入和输出,则将为16个字节(∧≜;1{j⊇Ċ+}ᵃ⁽.∋?∧),因为该程序的右侧将无法使用隐式约束(因此需要禁用该隐式约束,并提供一个新的显式约束,代价为2个字节)。

说明

∧≜;1{j⊇Ċ+}ᵃ⁽?∋
∧               Disable implicit constraint to read the left argument
 ≜;        ⁽    Evaluation order hint: minimize number of iterations
    {    }ᵃ     Repeatedly run the following:
   1      ᵃ       From {1 on the first iteration, results seen so far otherwise}
     j            Make {two} copies of each list element
      ⊇           Find a subset of the elements
       Ċ          which has size 2
        +         and which sums to {the new result for the next iteration}
             ∋    If the list of results seen so far contains {the right argument}
            ?     Output it via the left argument {then terminate}

有趣的是,在第一次迭代中会发生什么,输入是一个数字,而不是其他迭代中的列表。我们从数字1开始,每个数字制作两个副本(使数字11),然后找到它的2位数子序列(也就是数字11)。然后,我们将其数字总和取为2,这样序列就[1,2]可以按照我们的意愿开始了。在未来的迭代,我们开始与像一个列表[1,2],它要加倍[1,2,1,2],然后取两个元素的序列([1,1][1,2][2,1],或[2,2]); 显然,每一个的总和将成为加法链的下一个有效元素。

此处需要评估顺序提示,这尤其让人感到沮丧,尤其是组件(默认情况下,它是内部而不是外部获取评估顺序提示的,因此为了强制性问题而使用了粗略的用法)。


我尝试了大约30分钟,以找到解决此挑战的捷径。我的解决方案比这更长。
致命

1
@Fatalize:是很少出现的那些内置函数之一,但是当您需要它时,您确实需要它,因为没有使用其他控件构造来实现它的远程简洁方法。一旦我意识到这是一个挑战,剩下的就直接来自那里。

2

果冻,17个字节

’ŒP;€µ+þ;1Fḟ@µÐḟḢ

在指数时间内按字典顺序输出第一个解决方案。

在线尝试!

怎么运行的

’ŒP;€µ+þ;1Fḟ@µÐḟḢ  Main link. Argument: n (integer)

’                  Decrement; n-1.
 ŒP                Powerset; generate all subarrays of [1, ..., n-1], sorted first
                   by length, then lexicographically.
   ;€              Append n to all generate subarrays.
     µ       µÐḟ   Filterfalse; keep only subarrays for which the chain between the
                   two chain separators (µ) returns a falsy value.
     µ             Monadic chain. Argument: A (array of integers)
      +þ               Add table; compute the sums of all pairs of elements in x,
                       grouping the results by the right addend.
        ;1             Append 1 to the resulting 2D array.
          F            Flatten the result.
           ḟ@          Filterfalse swapped; remove all elements of A that appear in
                       the result. This yields an empty list for addition chains.
                Ḣ  Head; select the first result.

2

JavaScript(ES6),83 86字节

编辑:修复了以非反向顺序输出列表的问题

n=>(g=(s,a=[1])=>s-n?s>n||a.map(v=>g(v+=s,a.concat(v))):r=1/r|r[a.length]?a:r)(r=1)&&r

演示版


2

PHP,195字节

function p($a){global$argn,$r;if(!$r||$a<$r)if(end($a)==$argn)$r=$a;else foreach($a as$x)foreach($a as$y)in_array($w=$x+$y,$a)||$w>$argn||$w<=max($a)?:p(array_merge($a,[$w]));}p([1]);print_r($r);

在线尝试!


不幸的是,该算法无法给出最佳答案,例如15个。
Neil

@Neil现在更长了,但是可以使用。我目前不知道如何确定两种方式中的哪一种是正确的。也许素数起了作用
约尔格Hülsermann

此代码未通过149测试。长度应为10,而不是11
J42161217

@Jenny_mathy更正
约尔格Hülsermann

1

Mathematica,140个字节

t={};s={1};(Do[While[Last@s!=#,s={1};While[Last@s<#,AppendTo[s,RandomChoice@s+Last@s]]];t~AppendTo~s;s={1},10^4];First@SortBy[t,Length@#&])&

每次运行时都会产生不同的最短加法链

在线尝试
使用ctrl + v粘贴代码,将输入即[71]放在代码末尾,然后按shift + enter


由于我没有使用Mathematica的权限,因此输入15可提供多长的链?
尼尔

右边的一个{
1、2、3、5、10、15

3
对于输入149,我从您的程序中得到了一个长度为11的链,但是存在一个长度为10([1,2,4,5,9,18,36,72,77,149])的链。您的程序似乎使用随机抽样,因此不能保证找到最佳解决方案。
Zgarb

固定!但是需要更长的时间
J42161217 '17

1

Pyth,13个字节

h-DsM^N2/#QyS

测试套件

按字典顺序给出最短的链。速度相当慢,但还算不错-19使用pypy大约需要30秒即可完成。

@Dennis解决方案中的一些想法。

我真的很喜欢这个-涉及很多巧妙的技巧。

说明:

h-DsM^N2/#QyS
h-DsM^N2/#QySQ    Implicit variable introduction
            SQ    Inclusive range, 1 to input.
           y      Subsets - all subsets of the input, sorted by length then lexicographically
                  Only sorted subsets will be generated.
                  Our addition chain will be one of these.
        /#Q       Filter for presence of the input.
  D               Order by
 -                What's left after we remove
     ^N2          All pairs of numbers in the input
   sM             Summed
h                 Output the list that got sorted to the front.

这仍然很难理解,但让我尝试更详细地解释一下。

我们从开始ySQ,它给出了所有可能的有序子集[1, 2, ... Q]以大小的递增顺序。最短的加法链肯定是其中之一,但是我们需要找到它。

我们要做的第一件事是过滤列表以仅保留包含的列表Q。我们这样做/#Q

接下来,我们在删除某个函数的结果后,按剩下的顺序对列表进行排序。 -D除去某些东西后,按剩余订单排序。

我们删除的是sM^N2,我们要从中删除N的列表在哪里。^N2给出中的N两个元素的所有可能对的笛卡尔乘积NsM然后对每个对进行求和。

执行此删除操作后,最小的结果是什么?好吧,输入列表中的最小元素肯定会保留,因为所有数字都是正数,因此两个数字的任何和都将大于最小数字。至少会有一个数字,因为我们检查了输入是否存在于列表中。因此,最小的结果可能是,除最小数字外的每个数字都是列表中其他两个数字的总和,而列表中最小的数字是1。在这种情况下,排序键为[1]。这些要求意味着该列表必须是附加链。

因此,我们将附加链排序到最前面。请记住,y其子集的大小顺序递增,因此,排在最前面的列表必须是最短的加法链之一。h选择该列表。

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.