Wie kann ich einen Kassierer um Geld bei der Bank bitten?

35

Ich muss zur Bank gehen und etwas Geld abheben. Ich muss 30 $, 22 $ abheben, um meinen Mitbewohner für das Internet und 8 $ für die Wäsche zu bezahlen. Da sich an beiden nichts ändern kann, muss ich meine 30 US-Dollar in zwei Partitionen der beiden Größen aufteilen. Das heißt, wenn der Kassierer mich fragt, wie ich meine 30 Dollar haben möchte, muss ich eine Anfrage stellen. Ich könnte ihnen sagen, dass ich es in zwanzig, fünf und fünf haben will. Aber ich möchte meine Anfrage so einfach wie möglich machen, damit ich mich nicht wiederholen muss. Um meine Anfrage zu vereinfachen, könnte ich verlangen, dass mein Bargeld zwanzig und mindestens zwei enthält, da die 8 durch die Summe impliziert wird, aber noch besser, ich könnte einfach verlangen, dass eine der Rechnungen, die ich erhalte, eine Ein-Dollar-Rechnung ist (Wenn Sie Ich bin nicht davon überzeugt, versuche einfach 29 Dollar zu verdienen, ohne 8).

Das ist alles in Ordnung, aber ich muss diese Berechnung jedes Mal durchführen, wenn ich zur Bank gehe. Deshalb dachte ich, ich würde ein Programm schreiben, um dies zu tun.

Ihr Programm oder Ihre Funktion sollte eine Liste von ganzen Zahlen enthalten, die alle Zahlungen darstellen, die ich leisten muss, und eine Reihe von ganzen Zahlen, die die Nennwerte der bei der Bank verfügbaren Banknoten darstellen, und Sie müssen die kleinste Liste von Nennwerten so ausgeben, dass auf jede Weise die Summe gebildet wird Das schließt ein, dass die Liste der Stückelungen sauber in die Liste der Zahlungen unterteilt werden kann.

Extra Regeln

  • Sie können davon ausgehen, dass die Nennwertliste immer a enthält, 1oder Sie können sie jeder Liste selbst hinzufügen.

  • Einige Eingaben haben mehrere minimale Lösungen. In diesen Fällen können Sie beide ausgeben.

Dies ist daher werden die Antworten in Bytes bewertet, wobei weniger Bytes besser sind.

Testfälle

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}
Weizen-Assistent
quelle
22
Zuerst dachte ich, das sei Spam oder Off-Topic oder so ...
Erik the Outgolfer
1
@EriktheOutgolfer Absätze verletzt Herausforderungen so sehr> _ <
Magic Octopus Urn
2
Ich denke , Sie sollten mindestens einen Testfall enthalten , in dem der Antrag muss etwas anderes als Ein-Dollar - Scheine sein, wie {2,6} {1,2,7} -> {2}.
Arnauld
@ Arnauld Ich habe Ihren Fall hinzugefügt
Weizen-Assistent
1
(If you are not convinced of this just try to make 29 dollars without making 9)Du meinst ohne 8 zu machen? Oder habe ich falsch verstanden
undergroundmonorail

Antworten:

5

JavaScript (ES6), 485 476 Bytes

Okay ... das ist ein Monster. :-(
Aber es ist ein ziemlich schnelles Monster, das alle Testfälle fast augenblicklich löst.

Ich versuche vielleicht später etwas fortgeschritteneres Golfen, aber ich habe bereits viel zu viel Zeit damit verbracht.

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])

Testfälle

Wie?

NB: Dies stimmt nicht mehr mit der aktuellen Version überein, ist aber viel einfacher zu lesen.

// 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])
)
Arnauld
quelle
Ich kenne mich mit Javascript nicht so gut aus, aber können Sie das &&to &und das ||to reduzieren |?
Taylor Scott
@TaylorScott Dies ist nur unter bestimmten Bedingungen möglich. Zum Beispiel a || bwird bnur ausgewertet , wenn aes falsch ist, während a | bbedingungslos ein bitweises ODER zwischen aund ausgeführt wird b.
Arnauld
4

Python 2 , 456 455 Bytes

Extrem, extrem, extrem langsam !!!! Sollte bei genügend Zeit für alle Eingabebeispiele korrekt funktionieren

Bearbeiten: 1 Byte dank @Jonathan Frech gespeichert

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)

Probieren Sie es online!

Erläuterung

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)
Halvard Hummel
quelle
1
Mit eher eine Funktion als input()ist ein Byte kürzer .
Jonathan Frech