銀行で出納係にお金を尋ねるにはどうすればよいですか?


35

銀行に行ってお金を引き出す必要があります。私は30ドル、インターネットのためにルームメイトに支払うために22ドル、洗濯のために8ドルを引き出す必要があります。これらはどちらも変更できないため、30ドルを2つのサイズの2つのパーティションに分割する必要があります。つまり、窓口係から30ドルの支払い方法を尋ねられた場合、リクエストを行う必要があります。20、5、5枚で欲しいと伝えることができました。しかし、私は自分の要求をできるだけシンプルにして、自分自身を繰り返さなくても済むようにします。リクエストをより簡単にするために、合計で8が暗示されているため、現金に20個と2個以上を含めるように依頼できますが、受け取った請求書の1つが1ドルの請求書であることを要求できます( 8)を作らずに29ドルを作ろうとするだけです。

だからそれはすべてうまくいきますが、私は銀行に行くたびにこの計算を行う必要があるので、私はこれを行うプログラムを書くと思いました(私のためにこれを行うプログラムを書いてください)。

プログラムまたは関数は、私が行う必要のあるすべての支払いを表す整数のリストと、銀行で利用可能な請求書の額面を表す整数のセットを取り、すべての方法で合計を行うように、額面の最小リストを出力する必要がありますこれには、金種のリストを支払いのリストに明確に分割することができます。

追加ルール

  • 額面リストには常に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
最初は私が...これは、スパムまたはオフトピックか何かだと思った
エリックOutgolfer

1
@EriktheOutgolferの段落は非常に多くの課題を傷つける> _ <
マジックタコ

2
リクエストがのような1ドル札以外のものでなければならない場合、少なくとも1つのテストケースを含めるべきだと思います{2,6} {1,2,7} -> {2}
アーナルド

@Arnauldケースを追加しました
ウィートウィザード

1
(If you are not convinced of this just try to make 29 dollars without making 9)8を作らずに?または私は誤解した
地下

回答:


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を使用して、あまりにも慣れていないんだけど、あなたは減らすことができます&&&して|||
テイラースコット

@TaylorScottこれは特定の条件下でのみ可能です。たとえば、が偽である場合にのみa || b評価されますが、との間でビット単位のORを無条件に実行します。baa | bab
アーナルド

4

Pythonの2456の 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()ある1バイト短くなります
ジョナサン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.