八枚金币


22

这是另一个谜题的“对应”, Puzzling.SE上的公平之王的八枚硬币

您可以阅读以上背景拼图。有关此难题的详细信息如下。

创建了一组8种不同值的硬币,国王希望您找出最大的N,以便可以使用不超过8个硬币的组合并免费支付从0到N的任意数量的价格。

例如,(摘自Glorfindel的答案)。如果给出一组值分别为1、2、5、13、34、89、233、610的硬币,则程序应输出1596,因为0到1596(含)之间的每个数字都不能用总和表示给定列表中的8个数字(数字可以重复),而1597不能以这种方式表示。

以数学的方式,如果输入是由8个正整数组成的集合S,则所需的输出N满足对于介于0和N之间的任何数字n的情况,存在x1,x2,x3,...,x8,从而

x1+x2+...+x8=nandx1,x2,...,x8{0}小号

您的目标是编写一个程序,一个函数或一个片段,以8个数字作为输入,并如上所述输出最大N。

规则:

  • 允许灵活的I / O,因此您的程序可以采用最合适的任何形式进行输入。您可能会假设输入数字的排序方式最适合您的程序。
    • 如果您的程序取决于输入顺序,请在答案中注明
  • 输入是一组8个不同的正整数(无零)。输出是一个非负整数。
    • 如果输入集中没有1,则您的程序应输出0,因为从0到0的任何数字都满足要求。
    • 在输入无效的情况下(集合包含零,负或重复的数字),您的程序可以执行任何操作。
  • 禁止出现标准漏洞。
  • 您的程序应在几分钟后在现代计算机上运行。

测试用例(大部分取自有关“困惑”的链接问题下的答案):

[1, 2, 3, 4, 5, 6, 7, 8] => 64
[2, 3, 4, 5, 6, 7, 8, 9] => 0
[1, 3, 4, 5, 6, 7, 8, 9] => 72
[1, 2, 5, 13, 34, 89, 233, 610] => 1596
[1, 5, 16, 51, 130, 332, 471, 1082] => 2721
[1, 6, 20, 75, 175, 474, 756, 785] => 3356

这是一个,因此每种语言中最短的程序或代码片段将获胜!


1
这是个不错的难题,但是我个人认为,更多测试案例对测试我们提交的内容很有帮助。
Xcoder先生18年

将输入大小设置为参数会更好吗?暴力手段将与8斗争
Luis Mendo

1
@iBug然后,通常的规则类似于“应在一分钟之内在现代计算机上运行提交的内容”。这很模糊,但通常已经足够好了,因为蛮力和有效方法之间的差异非常大
Luis Mendo 18/12 /

1
您的时间限制为“几分钟”,仍然可以使用蛮力攻击。我的答案经过稍加修改后的版本会在我7岁的笔记本电脑上以1分20秒运行最后一个测试用例。
nimi

1
@Arnauld澄清
iBug

Answers:



9

果冻,12 字节

œċⱮ8Ẏ§ṢQJƑƤS

在线尝试!

在我的手机上的TIO上运行所有测试用例平均需要3.7秒,因此令人惊讶的是它相当快。

说明

œċⱮ8Ẏ§ṢQJƑƤS     Monadic link / Full program.
  Ɱ8             Promote 8 to [1 ... 8] and for each value k:
œċ                    Generate all combinations of k elements from the list.
    Ẏ§           Tighten, then sum. Flatten to a 2D list then sum each.
      ṢQ         Sort the result and remove equal entries.
        JƑƤ      For each prefix of this list, return 1 if it is equal to its length range, 0 otherwise.
           S     Finally, sum the result (counts the 1's which is equivalent to what is being asked).

7

Haskell,56个 50字节

g c=[x|x<-[1..],all((/=x).sum)$mapM(0:)$c<$c]!!0-1

在线尝试!

暴力手段。添加0到硬币列表,并尝试8种镐的所有组合。找到n不等于任何选择总和的第一个数字,然后返回n-1

大约需要5m30s [1, 2, 5, 13, 34, 89, 233, 610]我使用7岁的笔记本电脑硬件。

编辑:-6个字节,感谢@ØrjanJohansen

甚至更短的版本(-2字节,再次感谢@ØrjanJohansen)是

Haskell,48个字节

g c=[x|x<-[1..],all((/=x).sum)$mapM(:0:c)c]!!0-1

但是它会占用更多的内存,并且会在我的计算机上出现大量分页,并且无法“在几分钟内”完成。


1
您可以使用mapM(0:)$c<$c。(实际上mapM(:0:c)c应该可以,但是对于给定的测试用例,在TIO上会超时。)
ØrjanJohansen

4

果冻,9个字节

Żœċ8§ḟ’$Ṃ

在线尝试!

怎么运行的

Żœċ8§ḟ’$Ṃ  Main link. Argument: A (array)

Ż          Prepend a 0 to A.
 œċ8       Take all combinations of length 8, with repetitions.
    §      Take the sum of each combination.
       $   Combine the two links to the left into a monadic chain.
      ’      Decrement all sums.
     ḟ       Filterfalse; keep only sums that do not appear in the decremented sums.
        Ṃ  Take the minimum.

2
Żṗ8§ḟ’$Ṃ保存一个字节,但是我不确定8.5分钟是否算是几个字节。
丹尼斯


4

JavaScript(ES6), 100 88 80  76字节

这本质上是一种蛮力搜索,但是通过修剪可以加快搜索速度。在TIO上,测试用例的平均执行时间接近1秒。

假定输入数组从最高到最低排序。

a=>[...Array(a[0]*9)].findIndex(g=(i=8,s)=>s*i>0?a.every(x=>g(i-1,s-x)):s)-1

在线尝试!

已评论

a =>                      // a[] = input array
  [...Array(a[0] * 9)]    // create an array of 9 * max(a) entries
  .findIndex(             // find the position of the first truthy result
    g = (i = 8, s) =>     // g = recursive function taking a counter i, initialized to 8
                          //     and a sum s, initialized to the position in the above array
      s * i > 0 ?         //   if s is positive and i is not equal to 0:
        a.every(x =>      //     for each value x in a[]:
          g(i - 1, s - x) //       do a recursive call with i - 1 and s - x
        )                 //     end of every()
      :                   //   else:
        s                 //     yield s (s = 0 means success and makes findIndex go on)
  ) - 1                   // end of findIndex(); decrement the result


3

Pari / GP,57字节

a->n=-1;while(polcoeff((1+sum(i=1,8,x^a[i]))^8,n++),);n-1

在线尝试!


这是使用生成函数吗?
唐明

1
@donbright是的。
alephalpha

1
太棒了..并非强求解决方案的少数答案之一。许多语言可能没有内置多项式符号特征。Pari GP很酷。
唐明

2

Python 2中125个 115 111字节

lambda c:sum(i==j for i,j in enumerate(sorted(set(map(sum,product([0]+c,repeat=8))))))-1
from itertools import*

在线尝试!

需要整数列表作为输入。

说明:

# an anonymous function
lambda c:
                                                          # get all length-8 combinations of values, from (0,0,0,0,0,0,0,0) to (8,8,8,8,8,8,8,8)
                                                          # zero is added to ensure that combinations of fewer than 8 coins are represented Ex:(1,0,0,0,0,0,0,0)
                                                          product([0]+c,repeat=8)
                                                  # for each combination, sum the values
                                                  map(sum,.......................)
                                       # get unique values, then sort them smallest to largest
                                       sorted(set(................................))
             # for each index, value pair, return if the index is equal to the value
             i==j for i,j in enumerate(.............................................)
         # in Python arithmetic, False is 0 and True is 1. So, count how many items match their index.
         # Since zero was added to the list, there will always be one extra match (0==0). So offset by one.
         sum(........................................................................)-1
from itertools import*

2

Perl6,65个 63 41字节(39 37个字符)

{@_=(0,|@_)X+(0,|@_)for ^3;($_ if $_==$++for @_.sort.unique)-1}

在线尝试!

这是一个匿名块,将其数据作为数组传递。这(0,|@_)是添加0@_,即使它做了两次,它仍然是一个有点短于@_.push: 0;那么这将需要经过的空间_。这是一种蛮力方法,有点像是8种组合。交叉添加后,将为顺序值创建一个匿名列表。使用数学运算符时,列表会根据其长度进行求值,因此-1发挥了双重作用:占0并强制转换为Int。

这可能需要它的甜蜜时光,而是通过改变一个或两个(0,|@_)(0,|@_.unique)之前,首先for它可以显着加快。这会增加+7(运行时<60s)或如果您觉得第一个太慢(那么我对链接的代码进行此操作是为了避免60秒后超时),这会使分数 +14(运行时间<10s)。

编辑: JoKing在注释中对其进行了改进(相同的想法,交叉添加,然后返回最后一个连续的结果),使其达到惊人的39个字符(41个字节):

{(@_=@_ X+0,|@_)xx 3;first *+1@_,^∞}

在线尝试!

最终的列表不需要0,只需添加一次0就可以节省一些字节。该xx 3for循环模仿(仍然奶酪上的硬币是2的幂)。该first子返回无限列表中的第一个号码0..*^Inf也是可能的,但不保存空间),其+1不交叉添加列表中的一员。像我这样的,它的速度慢,所以加+7unique第一等号后,如果你觉得它太慢了指导方针。


1
48个字节。从技术上讲,这unique不是必需的,但它可以大大提高速度
Jo King

@JoKing很好,我不知道为什么我没有考虑使用xx。我知道必须有一种使用集合函数以更短的方式进行最终制表的方法,但是我的大脑无法正常工作。
user0721090601 18/12/28

xx 1应该是xx 3
乔金

@JoKing已修复。我也意识到两个字符(但没有字节)可以使用^∞
user0721090601

实际上,您可以使用(1...*∉@_)-1而不是使用来保存一些字节first(这与我在这里使用的方法相同)
Jo King

1

的JavaScript(Node.js的)171个 145 115字节

f=(s,n=3)=>n?f(s=new Set(a=[0,...s]),n-1,a.map(m=>a.map(n=>s.add(m+n)))):Math.min(...[...s].filter(m=>!s.has(m+1)))

在线尝试!@Mark的Python 3答案端口。在Firefox 30-57中为108个字节:

f=(s,n=3)=>n?f(new Set((for(n of s=[0,...s])for(m of s)n+m)),n-1):Math.min(...[...s].filter(m=>!s.has(m+1)))


0

干净,161字节

import StdEnv,Data.List
$l=:[1:_]#k=sort(nub(map sum(iter 8(concatMap(\[h:t]=[[e,h:t]\\e<-[0:l]|e>=h]))[[0]])))
=length(takeWhile((>=)1)(zipWith(-)(tl k)k))
$_=0

在线尝试!

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.