您可以制作多少个三果馅饼?


32

三果馅饼由三种不同的水果制成。从您拥有的5种水果中最多可以制成三种水果派?

例如,

1 apple
1 banana
4 mangoes 
2 nectarines
0 peaches

您可以制作2个馅饼:

apple, mango, nectarine
banana, mango, nectarine

输入:五个非负整数或它们的列表。

输出:可以从这些数量的水果中制作出最多三个水果馅饼。最少的字节数获胜。

测试用例:

1 1 4 2 0
2
2 2 2 2 2
3
0 6 0 6 0
0
12 5 3 2 1
5
1 14 14 3 2
6
0 0 1 0 50
0

排行榜:


我相信您的示例缺少两个其他选项:Apple,Banana,Mango和Apple,Banana,Nectarine。因此,1 1 4 2 0测试用例应该产生输出:4.
cobaltduck

@cobaltduck但是,如果您在第一个饼图(Apple / Banana / Mango)中使用了Apple和Banana,则您的第二个饼图(Apple / Banana / Nectarine)中没有使用Apple或香蕉。
AdmBorkBork,2015年

2
@Timmy D:知道了。目前尚不清楚这些馅饼是同时制作的。
cobaltduck

@cobaltduck我相信不必同时制作它们,但是您不能通过重复使用用于第一个的水果来作弊。
李斯特先生,2015年

@先生。李斯特:语义学。(对于至少一个读者而言)有一个模棱两可的规则并自那时以来已经阐明就足够了。
cobaltduck 2015年

Answers:


34

Pyth,19 18 14字节

-1字节@FryAmTheEggman

@isaacg提供的14字节程序

我声称可以从升序列表中形成的饼数[x1,x2,x3,x4,x5]为:

floor(min((x1+x2+x3+x4+x5)/3,(x1+x2+x3+x4)/2,x1+x2+x3))

或在代码中:

JSQhS/Ls~PJ_S3

[请参阅TI-BASIC和APL程序的修订历史记录]

正确性证明

s3 = x1+x2+x3
s4 = x1+x2+x3+x4
s5 = x1+x2+x3+x4+x5

我们要证明的P(X)=floor(min(s5/3,s4/2,s3))是,对于1〜5个x1≤x2≤x3≤x4≤x5水果数量列表,最大的馅饼数总是最大的。

首先,我们证明所有三个数字都是上限。

  • 由于s5总共有水果,每个馅饼有三个水果,因此⌊s5/3⌋是一个上限。

  • 由于存在的s4水果不是水果5,每个饼至少需要两个非5的水果,因此这⌊s4/2⌋是上限。

  • 由于存在s3既不是水果4也不是水果5的水果,并且每个饼中至少需要一个这样的水果,因此s3是上限。

其次,我们表明从三个最大的桩中获取果实的方法始终可以满足要求。我们通过归纳来做到这一点。

基本情况:显然可以从任何有效列表中形成0个饼P(X)>=0

归纳步:给定任何名单X,其中P(X) > 0,我们可以烤馅饼一个,留下一个列表X'P(X') >= P(X)-1。为此,我们从最大的三堆水果中取出3,4,5,然后根据需要采取措施。忍受我 有一些案例。

  • 如果为x2<x3,则删除水果后我们不需要对列表进行排序。我们已经有一个有效的X'。我们知道,P(X') = P(X)-1因为s5'少了3个(因为删除了1〜5型的三个水果),s4'少了2个且少了s3'1个。因此P(X'),正好比P(X)小1。
  • 如果为x3<x4,则我们同样完成。
  • 现在我们来看一下x2=x3=x4。这次我们需要重新排列列表。

    • 如果x5>x4,则我们通过切换桩4和2来重新排列列表,s5'并且s4'仍然分别减少3和2,但是s3'=s3-2。这不是问题,因为if x2=x3=x4,那么2*x4<=s3-> 2*x4+s3 <= 2*s3-> (x4 + s4)/2 <= s3。我们有两个子情况:
    • 相等,即(x4,x3,x2,x1)=(1,1,1,0)在这种情况下P(X)= 1,我们可以明显地从堆中制成饼图5,4,3,或者:

    • (s4+1)/2 <= s3在这种情况下减少s4通过额外的1,并不意味着额外降低到P(X)。

  • 现在我们剩下其中的情况了x1<x2=x3=x4=x5。现在,s3也将受到1会下降,因此我们需要(s5/3+1)<=s4/2; 即8x5+2x1+2<=9x5+3x1x5+x1>=2。小于此的所有情况都可以手动检查。

  • 如果每个数字都相等,则很明显,我们可以实现的界限⌊s5/3⌋,该界限始终小于其他两个界限-我们只需按顺序遍历这些数字即可。

最后,我们完成了。如果我缺少某些东西,请发表评论,我将提供一笔小小的赏金,以提供更优雅的证明。


我认为您的主张与@fryamtheeggman的迭代解决方案相符。
Sparr 2015年

@Sparr我正在尝试使用fryamtheeggman的方法来证明我的范围是可以达到的。
lirtosiast,2015年

2
可以将其变成一个循环,从而将其压缩4个字节:JSQhS/Ls~PJ_S3
isaacg 2015年

3
我相信我已经找到了每个派的n成分和k成分的证明,但是对于此注释框来说太长了。请指出您可能会发现的任何错误,以便我们证明这一点。
Mego

7

CJam,34岁

q~L{J2be!\f{\.-_W#){j)7}|;}0+:e>}j

在线尝试

说明:

q~          read and evaluate the input array
L{…}j       calculate with memoized recursion and no initial values
             using the input array as the argument
  J2b       convert 19 to base 2 (J=19), obtaining [1 0 0 1 1]
  e!        get permutations without duplicates
             these are all the combinations of three 1's and two 0's
             which represent the choices of fruit for one pie
  \         swap with the argument array
  f{…}      for each combination and the argument
    \       swap to bring the combination to the top
    .-      subtract from the argument array, item by item
    _       duplicate the resulting array
    W#)     does it contain the value -1? (calculate (index of W=-1) + 1)
    {…}|    if not
      j     recursively solve the problem for this array
      )7    increment the result, then push a dummy value
    ;       pop the last value (array containing -1 or dummy value)
  0+        add a 0 in case the resulting array is empty
             (if we couldn't make any pie from the argument)
  :e>       get the maximum value (best number of pies)

记住递归会花费字节吗?没有运行时间限制。
xnor 2015年

2
@xnor我认为它实际上在这里节省了1个字节:)
aditsu

7

Haskell,62个字节

f x=maximum$0:[1+f y|y<-mapM(\a->a:[a-1|a>0])x,sum y==sum x-3]

这定义了一个功能 f接受水果列表x并返回最大馅饼数的。

说明

我们递归计算派的数量。该部分mapM(\a->a:[a-1|a>0])x将对x通过递减任何肯定条目而获得的所有列表求值。如果x = [0,1,2],结果为

[[0,1,2],[0,1,1],[0,0,2],[0,0,1]]

外层之间的部分[]是列表理解:我们遍历y上面列表中的所有列表,并筛选出总和不等于的sum(x)-3列表,因此我们得到了将3种不同的水果制成饼图的所有列表。然后,我们f对这些列表进行递归求值,添加1到每个列表中,并采用它们的最大值和0(基本情况,如果我们不能做任何馅饼)。


7

C#,67

在每次迭代中递归地制作一个派,使您拥有最多的水果,直到用完为止。

int f(List<int>p){p.Sort();p[3]--;p[4]--;return p[2]-->0?1+f(p):0;}

这里的测试用例


不熟悉C#,但是您也许可以p[2]--在检查的同时进行p[2]>-1
xnor 2015年

好点,我将在一秒钟内更新答案。
AXMIM 2015年

6

佩斯,29岁

Wtt=QS-Q0=Q+tPPQtM>3.<Q1=hZ;Z

测试套件

对输入列表进行排序并删除零。然后,只要您有3个水果,就递减第一个和最后两个元素,然后将剩余的元素添加到列表中,然后对其进行排序并再次删除零。然后将计数器加1。

只要只有5个水果,这实际上是相当快的,它可以解决很大的水果箱,即1000,1000,1000,1000,1000不到一秒钟。


你能证明它是正确的吗?
aditsu

@aditsu我还没有证明,但是我与您的作了比较,以确定它的几个附加值。之前我还没有为这样的事情写过证明,但是我会尽力的。现在,我会说它应该起作用是有道理的,因为您总是只从最大的水果堆中取出,直到耗尽较小的水果。尽管贪婪策略显然并不总是固有地正确,但我无法想到为什么它在这里不起作用。
FryAmTheEggman

@FryAmTheEggman我明白你拿了两种最常见的水果和最稀有的水果吗?
xnor 2015年

@xnor是的,这是正确的。那行不通吗?
FryAmTheEggman

1
@TimmyD不,我没有(想我),但是删除此功能不需要花费任何字节(实际上花费更多)。也就是说,我希望Reto Koradi的解决方案在大多数语言中都更短,并且显然Thomas的解决方案要简洁得多。我认为您不必重新排序的原因与您从3个较小的桩中取哪个无关。
FryAmTheEggman

6

Python,一般解决方案,128 92字节

来自@xnor的-36字节,您是真正的MVP

g=lambda l,k:0if k>sum(l)else-(-1in l)or-~g(map(sum,zip(sorted(l),[0]*(len(l)-k)+[-1]*k)),k))

def g(a,k):b=[i for i in a if i];return 0if len(b)<k;c=sorted(b,reverse=True);return 1+g([c[i]-(k-1>i)for i in range(len(c))],k)

只要我的证明是正确的,就是可行的。如果不是,请告诉我原因,以便我尝试修复它。如果无法理解,请告诉我,几杯咖啡后我会攻击它。


现在一切对我来说似乎都很紧张。
lirtosiast 2015年

@Mego感谢您为此工作!您能否将证明包括在SE职位中?人们普遍担心,几年后阅读此书的人可能会发现死链接。LaTeX格式应该基本上只适用于MathJax。
xnor 2015年

@Mego糟糕,我忘记了此处未启用MathJax。嗯,我问该怎么办。
xnor 2015年

我授予这个证明的赏金。恭喜!
xnor

@Mego Nope,我认为您的MathCloud链接是我们拥有的最好的链接。
xnor

5

Python 2,78个字节

以5个数字作为输入: 91 89 88字节

s=sorted([input()for x in[0]*5])
while s[2]:s[2]-=1;s[3]-=1;s[4]-=1;s.sort();x+=1
print x

编辑s=sorted([input()for x in[0]*5])通过更改s=sorted(map(input,['']*5));x=0保存1个字节。

以5个数字作为输入,并打印可以制作的可能的饼数。它采用与Reto Koradi的答案相同的方法-并没有提高字节数-但感觉这个问题在Python中缺少答案。

感谢@ThomasKwa和@xsot的建议。

怎么运行的

 s=sorted([input()for x in[0]*5]) takes 5 numbers as input, puts them in a list 
                                  and sorts it in ascending order. The result
                                  is then stored in s 

 while s[2]:                      While there are more than 3 types of fruit 
                                  we can still make pies. As the list is                     
                                  sorted this will not be true when s[2] is 0. 
                                  This takes advantage of 0 being equivalent to False.

 s[2]-=1;s[3]-=1;s[4]-=1          Decrement in one unit the types of fruit 
                                  that we have the most

 s.sort()                         Sort the resulting list

 x+=1                             Add one to the pie counter

 print x                          Print the result

请注意,x从未定义变量,但是程序利用了python 2.7带来的某些泄漏。s用列表理解定义列表时,可迭代的最后一个值([0]*5在这种情况下)存储在用于迭代的变量中。

为了使事情更清楚:

>>>[x for x in range(10)]
>>>x
9

以清单为输入:78个位元组

感谢@xnor @xsot和@ThomasKwa建议将输入更改为列表。

s=sorted(input());x=0
while s[2]:s[2]-=1;s[3]-=1;s[4]-=1;s.sort();x+=1
print x

怎么运行的

它的工作方式与上面的代码相同,但是在这种情况下,输入已经是列表,因此无需创建它和变量 x必须定义。

免责声明:这是我第一次尝试打高尔夫球,并且感觉它仍然可以打高尔夫球,因此建议您进行一些更改以减少字节数。


1
允许您将输入内容包含在列表中;s[2]>0-> s[2],因为堆中的数字始终为非负数。
lirtosiast 2015年

托马斯·夸(Thomas Kwa)指出,您可以假设输入已作为列表给出,因此您可以这样做s=sorted(input())。另外,您当前的字节数为89;换行符视为一个字符。
xnor 2015年

@ThomasKwa已经指出您可以接受输入作为列表,但是如果您坚持接受多行输入,请用以下内容替换第一行以保存一个字节:s=sorted(map(input,['']*5));x=0
xsot

4

CJam,23个字节

0l~{\)\$2/~+:(+_2=)}g;(

在线尝试

这样可以从每次迭代的3个最大堆中获取结果,并计算迭代次数。

我没有数学证明可以始终给出正确的结果。它适用于给定的测试示例,并且我相信它会在所有情况下都有效,直到有人给我提供反示例为止。

我曾经说服自己的直观解释:为了最大化派的数量,您需要保持尽可能多的非空堆。这是因为一旦您拥有3个或更多的空堆,您就会失去制作更多馅饼的能力。

这是通过始终从最大的堆中获取水果来实现的。我想不出比从大堆里拿水果更好的情况。

我脑子里有些正式的推理。我将尝试思考一种将其放入单词/公式的方法。


我一直在尝试使用归纳法。也许我们可以结合我们的想法找到正式的证明。
lirtosiast 2015年

@ThomasKwa我还没有想出足够清晰的东西,如果我写下来的话,这听起来似乎很有说服力。归结为这样一个事实,我绝对没有理由认为从较小的堆栈中取走更大的堆栈会更好。尽管在某些情况下,从较小的堆栈中获取数据会更糟。我还为我的和aditsu的解决方案输入了一些随机的适度大数,它们产生了相同的结果。我的解决方案也与您尝试的示例的公式一致。
Reto Koradi

3

> <>,​​76个字节

0&4\/~}&?!/
@:@<\!?:}$-1@@$!?&+&:)@:@
,:&:@(?$n;/++:&+::2%-2,:&:@(?$&~+:3%-3

原来,对> <>进行排序并不容易!该程序依赖于Thomas Kwa提出的证明是正确的,当然,测试用例也是如此。

程序启动时,预计5个输入数字将出现在堆栈中。

前两行对堆栈上的数字进行排序,第三行执行计算floor(min((x1+x2+x3+x4+x5)/3,(x1+x2+x3+x4)/2,x1+x2+x3))(取自Thomas的答案)。


如果您计算所有三个/四个元素的总和以及它们的最小值,它会更短吗?
lirtosiast,2015年

@ThomasKwa我看起来像是要找到输入集的排列,将每个元素的最上面的3个和4个元素相加,然后取最小的那些元素?我认为找到排列不会比我使用的排序/计算方法短,尤其是在基于堆栈的语言中。如果知道任何方便的算法来生成基于堆栈的语言的排列,我很想看看:o)
Sok 2015年

2

Python 2,59个字节

h=lambda l,k=3:k*'_'and min(h(sorted(l)[:-1],k-1),sum(l)/k)

适用于n和的通用方法k。在k=3使每饼默认的水果3,但你可以在不同的值传递。递归使用字符串大于Python 2中的数字这一事实,让空字符串代表无穷大的基本情况。

此方法利用始终选择最常见的水果是最佳的事实,因此我们将每种可能的水果等级视为限制因素。我在下面证明了这一事实。


Mego的证明让我想到了这个更直接的证明,即反复摘取最常见的果实是最优的。这是用k水果馅饼来说明的。

定理:反复服用k最常见的果实可得到最佳的派数。

证明:我们将证明,如果N可能有饼,那么最常见的水果策略至少会产生N饼。为此,我们在各个N馅饼之间切换果实,以使其与该策略产生的果实相匹配,同时保持馅饼的有效性。

让我们使其成为第一个馅饼(称为p)包含最常见的水果。如果还没有,它必须包含一种水果i,但不能包含更常见的水果j。然后,其余的饼中所含的水果j要严格得多于水果i,因此其他一些派q必须包含j但不包含i。然后,我们可以交换水果i从馅饼p水果j从馅饼q,这使N具有不同的水果馅饼。

重复此过程,直到p获得k最常见的果实。

然后,将饼p放在一边,对下一个饼重复此过程,以使其剩下的果最普通。继续这样做,直到馅饼成为最常见的水果策略产生的序列。


1

PowerShell,92字节

$a=($args|sort)-ne0;while($a.count-ge3){$a[0]--;$a[-1]--;$a[-2]--;$a=($a-ne0;$c++}($c,0)[!$c]

使用与FryAmTheEggman的答案相同的基于贪婪的算法...在PowerShell中使用起来更加冗长。

$a=($args|sort)-ne0  # Take input arguments, sort them, remove any 0's
while($a.count-ge3){ # So long as we have 3 or more fruit piles
  $a[0]--            # Remove one from the first element...
  $a[-1]--           # ... the last element ...
  $a[-2]--           # ... and the second-to-last.
  $a=$a-ne0          # Remove any 0's from our piles
  $c++               # Increment how many pies we've made
}                    #
($c,0)[!$c]          # Equivalent to if($c){$c}else{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.