触发斜槽并保护头奖


23

您将要参加游戏节目。挑战之一如下:

  • 第一个房间包含大量相同的球。
  • 第二个房间包含一系列滑槽,每个滑槽都具有一个传感器,该传感器可以计算放置在其中的球的数量。放置在滑槽中的球将无法回收。
  • 在将一定数量的球(其触发计数)放入其中后,每个滑槽都将触发。当它触发时,它会闪烁灯光,发出声音并毫无疑问地触发它。
  • 您必须触发N滑道才能继续下一个挑战。
  • 您知道触发计数,但不知道计数与斜道之间的对应关系。
  • 您有机会将球从第一个房间带到第二个房间。将球放入滑槽后,您将无法再返回更多球。
  • 您拿到的每个球都会从累积奖金中扣除。

显然,您想确保自己能够通过挑战,但是想要最大程度地减少累积奖金损失。编写程序,函数,动词等以告诉您您需要多少个球。

假设触发计数为2、4和10,并且您需要触发2个滑槽才能通过。有一个策略,可以传10个球:在第一个溜槽中最多放置4个球,在第二个溜槽中最多放置4个球,在第三个溜槽中最多放置4个球。由于三个滑道之一仅在触发2个球后才触发,因此您总共只能使用10个球。没有可以保证少于10个的策略,因此这是正确的输出。

输入项

输入由一个整数触发计数的数组和一个给出要触发的溜槽数的整数组成。您可以按任意顺序输入两个输入,并且如果需要,可以输入第三个输入与数组的长度。

您可以假设所有输入均大于零,并且必须触发的溜槽数量不超过溜槽数量。

您还可以假设计数是排序的(升序或降序),只要您在回答中清楚说明即可。

输出量

输出应为单个整数,给出最佳策略所需的球数。

测试用例

格式: N counts solution

1 [2 4 10] 6
2 [2 4 10] 10
3 [2 4 10] 16
1 [3 5 5 5 5 5 5 5 5 5] 5
2 [1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 8 11] 8
2 [1 2 6 6 6 6 6 6 6 10] 16
2 [1 2 3 3 4 4 6 6 6 11] 17
3 [1 2 3 4 5 5 6] 16
3 [2 4 7 7 7 7 7 7 7] 21
5 [1 2 2 3 3 3 3 3 5 9 9 11] 27
2 [5 15 15] 25
1 [4 5 15] 10
3 [1 4 4 4] 10
2 [1 3 4] 6
2 [1 3 3 8] 8

警告:不要尝试忍者!
暴民埃里克(Erik the Outgolfer)'17年

1
您能解释一下为什么最后一个测试用例给出10吗?为了确保至少一个触发器,每个都不应该至少放置4个吗?我可能太笨了,对问题的理解不够充分,但我不明白。
Xcoder先生17年

2
@Rod您只需要在其中两个中放置5,然后再保证其中一个会触发,则5 * 2 = 10
H.PWiz

3
@ H.PWiz谢谢,现在知道了。我们面临的挑战似乎更为复杂,现在....
Xcoder先生

1
@ Mr.Xcoder,是的,但是在最坏的情况下,您必须确保成功。
彼得·泰勒

Answers:


4

Python,第222个 198字节

def S(G,P,T=0):
 T=T or[0]*len(P);r=[0]*(sum(t>=p for t,p in zip(T,P))>=G)
 for i,t in enumerate(T):
    if t<max(P):a=next(p for p in P if p>t)-t;T[i]+=a;r+=[a+S(G,P,sorted(T))];T[i]-=a
 return min(r)

用法是S(2, (2, 4, 10))

为了以任何适当的速度测试该程序,请在函数定义之后添加备忘录,以添加备忘录:

old_s = S
mem = {}
def S(G, P, T=0):
    k = (G, tuple(P), T and tuple(T) or 0)
    if k in mem: return mem[k]
    r = old_s(G, P, T)
    mem[k] = r
    return r

我们对数组T进行动态编程,数组T包含我们投入每个滑槽的球的数量,最初是全零。在没有提供严格证据的情况下,我声称我们可以始终使T保持排序,即假设我们总是将最多的球扔到最后一个滑槽中,而这又将是最大的滑槽。

如果当T与P匹配的元素(这是我们的问题输入)匹配的元素至少具有G(这是我们的目标)个元素更大时,我们找到了一个解决方案,并且返回0,因为我们需要抛出0寻找更多解决方案的球。这意味着,如果G为1,则我们投入最少的滑道必须包含的球数量等于或大于最小滑道的要求,以此类推,对于更大的G,依此类推。

否则,对于每个位置,我们都投入足够的球来升级到下一个滑槽要求(介于两者之间的任何东西都将不可观察)并递归。然后,我们返回这些递归调用中的最小值。


删除215个字节continue
Xcoder先生17年


4

Haskell,124 117 100 98 91 80 78字节

@Peter Taylor节省了11个字节

0#_=0
n#a=minimum$zipWith(\x y->x*y+(n-1)#(snd.splitAt y$a))a[1..length a-n+1]

在线尝试!

(#)接受一个整数和一个以降序排列的整数列表作为参数

用法是 1#[10,4,2]

说明:

对于列表中位置i(1表示)的每个值x,删除该元素(或某些数量小于或等于x的元素)的最佳策略是将x个球倒入i滑槽。

对于每个元素x,在列表中位置i处,(n#)计算列表中位置i之外的x * i +((n-1)#)(直到n为0)。然后,它需要检查的所有可能性中的最小值。


3

Haskell,54个字节

(%)0
(p%l)n|h:t<-l=p+min(p%t$n)(h%t$n-1)|n<1=p|1>0=1/0

在线尝试!

以升序排列列表。


自我注意:下一次坚持输出应为整数类型。
彼得·泰勒

1
我对Haskell的了解不够多,您能否加上一个解释?
orlp

2

Python,73个字节

f=lambda n,c:n and min(c[i]*-~i+f(n-1,c[-~i:])for i in range(len(c)-n+1))

H.PWiz的Haskell答案端口。要求输入按降序排列。


1

CJam(35字节)

{:A,,e!f<{$__(;A,+.-\Af=.*1bz}%:e<}

在线演示

将输入作为N counts假设counts以升序排序。

解剖

将计数按降序表示为1索引数组C(因此,第二个元素C是第二大计数)。假设我们最终通过触发溜槽而获胜C[a_0], C[a_1], ... C[a_{N-1}]。然后,在最坏的情况下,对于每个滑道,C[a_i]我们至少要向C[a_i]每个滑道中放入球。所以我们把球放入槽,一个额外的球放入其中,...1a_iC[a_{N-1}]a_{N-1}C[a_{N-2}]a_{N-2}

在每个N计数子集上,哪一个给我们最小的总和?然后,我们应该努力赢得那部分计数。

注意:代码实际上以升序使用计数,但是我认为降序更直观。

{         e# Define a block
  :A      e#   Store the sorted counts as A
  ,,e!f<  e#   Get all N-element subsets of A's indices
  {       e#   Map over these subsets S:
    $__   e#     Sort the subset and get a couple of copies
    (;A,+ e#     Remove the first element from one copy and append len(A)
    .-    e#     Pointwise subtraction, giving [S[0]-S[1] S[1]-S[2] ...]
    \Af=  e#     Get the counts [A[S[0]] A[S[1]] ...]
    .*    e#     Pointwise multiplication
    1bz   e#     Sum and take absolute value, giving the worst case score
  }%
  :e<     e#   Select the minimum worst case score
}
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.