我如何向银行的柜员要钱?


35

我需要去银行取一些钱。我需要提取30美元,22美元来支付我的室友的上网费以及8美元的洗衣费。由于这些都不能改变,我需要将$ 30分成两个大小的两个分区。这意味着当出纳员问我如何要我的30美元时,我将不得不提出请求。我可以告诉他们我要二十,五个和五个。但是我想使我的请求尽可能简单,以避免重复自己。为了使我的请求更简单,我可以要求我的现金包含20个现金,并且至少包含2个现金,因为总数暗示了8个现金,但更好的是,我可以简单地要求我收到的钞票中的一个是一美元的钞票(如果您不相信这一点,只需尝试赚29美元而不赚8)。

这样很好,但我每次去银行时都需要进行此计算,所以我想我会写一个程序来执行此操作(您是否已编写一个程序来为我执行此操作)。

您的程序或函数应使用代表我需要进行的所有付款的整数列表和代表银行可用的纸币面额的一组整数,并且您必须输出最小面额的列表,以使每种方式都能得出总计包括该种面额的清单可以清晰地分为付款清单。

额外规则

  • 您可以假定面额列表将始终包含a 1,也可以将其自己添加到每个列表中。

  • 一些输入将具有多个最小解决方案。在这些情况下,您可以输出其中之一。

这是因此答案将以字节计分,而字节数越少越好。

测试用例

Payments, denominations    -> requests
{22,8}    {1,2,5,10,20,50} -> {1} or {2}
{2,1,2}   {1,5}            -> {1}
{20,10}   {1,2,5,10,20,50} -> {}
{1,1,1,1} {1,2}            -> {1,1,1}
{20,6}    {1,4,5}          -> {1}
{2,6}     {1,2,7}          -> {2}
{22, 11}  {1, 3, 30, 50}   -> {1, 3}
{44, 22}  {1, 3, 30, 50}   -> {1, 3, 3, 30}

22
起初我以为这是垃圾邮件或垃圾邮件之类的东西……
Erik the Outgolfer

1
@EriktheOutgolfer段落严重伤害了挑战> _ <
Magic Octopus Urn

2
我认为您应该至少包括一个测试用例,其中请求必须不是一美元的帐单,例如{2,6} {1,2,7} -> {2}
Arnauld

@Arnauld我已经添加了您的案例
Wheat Wizard

1
(If you are not convinced of this just try to make 29 dollars without making 9)你的意思是不进8?还是我误会了
Undergroundmonorail

Answers:


5

的JavaScript(ES6),485个 476字节

好吧...这是一个怪物。:-(
但这是一个相当快的怪物,几乎可以立即解决所有测试用例。

以后我可能会尝试一些更高级的高尔夫球,但是我已经花了太多时间。

f=(b,a,L=[...a])=>L.reduce((a,x)=>[...a,...a.map(y=>[x,...y])],[[]]).sort((a,b)=>a[b.length]||-1).find(L=>(Y=G(U(b)-U(L),L.sort((a,b)=>a-b)),Y[0]&&!Y.some(a=>P(b.map(a=>G(a,[]))).every(b=>b+''!=a))),U=a=>~~eval(a.join`+`),P=(e,C=[],R=[])=>e[0].map(v=>R=(c=v.map((x,i)=>x+(C[i]|0)),e[1])?[...P(e.slice(1),c),...R]:[c,...R])&&R,G=(n,l)=>(S=[],g=(n,l)=>n?a.map(x=>x<l[0]|x>n||g(n-x,[x,...l])):S=[l.map(v=>s[a.indexOf(v)]++,s=[...a].fill(0))&&s,...S])(n,l)&&S)||f(b,a,[...a,...L])

测试用例

怎么样?

注意:这不再与当前版本匹配,但是用这种方式更容易理解。

// b = list of payments, a = list of bills,
// L = list from which the requested bills are chosen
f = (b, a, L = [...a]) => (
  // U = helper function that computes the sum of an array
  U = a => ~~eval(a.join`+`),

  // P = function that computes the summed Cartesian products of arrays of integers
  // e.g. P([[[1,2],[3,4]], [[10,20],[30,40]]]) --> [[33,44], [13,24], [31,42], [11,22]]
  P = (e, C = [], R = []) => e[0].map(v => R =
    (c = v.map((x, i) => x + (C[i] | 0)), e[1]) ? [...P(e.slice(1), c), ...R] : [c, ...R]
  ) && R,

  // G = function that takes a target amount and a list of requested bills and returns
  // all combinations that contain the requested bills and add up to this amount;
  // each combination is translated into a list of number of bills such as [2,0,0,1,0]
  G = (n, l) => (
    S = [],
    g = (n, l) => n ?
      a.map(x => x < l[0] | x > n || g(n - x, [x, ...l])) :
      S = [l.map(v => s[a.indexOf(v)]++, s = [...a].fill(0)) && s, ...S]
  )(n, l) && S,

  // compute X = list of possible bill combinations to process all payments
  X = P(b.map(a => G(a, []))),

  // compute the powerset of L and sort it from shortest to longest list
  L.reduce((a, x) => [...a, ...a.map(y => [x, ...y])], [[]])
  .sort((a, b) => a[b.length] || -1)

  .find(L => (
    // compute Y = list of possible combinations to reach the total amount,
    // using the requested bills
    Y = G(U(b) - U(L), L.sort((a, b) => a - b)),

    // exit if Y is not empty and all combinations in Y allow to generate all payments
    Y[0] && !Y.some(a => X.every(b => b + '' != a)))
  )

  // if no solution was found, enlarge the set of requested bills and try again
  || f(b, a, [...a, ...L])
)

我对javascript不太熟悉,但是可以将&&to &||to 减少|吗?
泰勒·斯科特

@TaylorScott这仅在某些条件下才可能。例如,a || bb仅在a为falsy时求值,而a | b将无条件地在a和之间执行按位或运算b
Arnauld

4

Python 2中456个 455字节

极其非常慢!!!! 如果有足够的时间,应该可以在所有输入示例上正常工作

编辑:感谢@Jonathan Frech,保存了1个字节

def F(p,d):v=sum(p);E=enumerate;l=lambda x,y:y[1:]and(x>=y[-1]and[k+[y[-1]]for k in l(x-y[-1],y)]+l(x,y[:-1])or l(x,y[:-1]))or[[1]*x];Q=l(v,d);m=lambda x,y=[0]*len(p):x and max(m(x[1:],[a+x[0]*(i==j)for i,a in E(y)])for j,_ in E(y))or y==p;f=lambda x,h=[]:x and min([S for i,s in E(x)for S in h+[s],f(x[:i]+x[i+1:],h+[s])if all(map(m,filter(lambda k:all(k.count(j)>=S.count(j)for j in S),Q)))],key=len)or[1]*v;print-(all(map(m,Q))-1)*min(map(f,Q),key=len)

在线尝试!

说明

p,d=input() # Read input
v=sum(p) # Save a byte by keeping track of the total money withdrawn
E=enumerate # We use enumerate a lot
# Generates the possible combinations of denominators that add up to the withdrawn amount 
l=lambda x,y:y[1:]and(x>=y[-1]and[k+[y[-1]]for k in l(x-y[-1],y)]+l(x,y[:-1])or l(x,y[:-1]))or[[1]*x]
# We use the list generated by l quite a few times
Q=l(v,d)
# Checks if we can divide a list of denominators x in such a way that we get the wished division of the money
m=lambda x,y=[0]*len(p):x and max(m(x[1:],[a+x[0]*(i==j)for i,a in E(y)])for j,_ in E(y))or y==p
# For a list of denominators, it tries all possible combinations of the denominators as input to the teller, selecting the one with minimum length
f=lambda x,h=[]:x and min([S for i,s in E(x)for S in h+[s],f(x[:i]+x[i+1:],h+[s])if all(map(m,filter(lambda k:all(k.count(j)>=S.count(j)for j in S),Q)))],key=len)or[1]*v
# Call f with all possible lists of denominators, and check if saying nothing to the teller will work
print-(all(map(m,Q))-1)*min(map(f,Q),key=len)

1
使用功能,而不是input()一个字节的短
乔纳森·弗雷希
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.