Come posso chiedere denaro a un cassiere in banca?


35

Devo andare in banca e ritirare del denaro. Devo prelevare $ 30, $ 22 per pagare il mio compagno di stanza per Internet e $ 8 per il bucato. Poiché nessuno di questi può apportare modifiche, ho bisogno che i miei $ 30 siano divisi in due partizioni delle due dimensioni. Ciò significa che quando il cassiere mi chiede come voglio i miei $ 30 dovrò fare una richiesta. Potrei dire loro che lo voglio tra venti, cinque e cinque. Ma voglio rendere la mia richiesta il più semplice possibile per evitare di dovermi ripetere. Per semplificare la mia richiesta, potrei chiedere che il mio contante contenga venti e almeno 2 perché l'8 è implicito nel totale, ma meglio potrei semplicemente richiedere che una delle fatture che ricevo sia una banconota da un dollaro (Se tu non ne sono convinto provate a fare 29 dollari senza farne 8).

Quindi va tutto bene e dandy ma ho bisogno di fare questo calcolo ogni volta che vado in banca, quindi ho pensato di scrivere un programma per farlo (hai scritto un programma per farlo per me).

Il tuo programma o funzione dovrebbe prendere un elenco di numeri interi che rappresentano tutti i pagamenti che devo effettuare e un set di numeri interi che rappresentano le denominazioni delle fatture disponibili in banca, e devi produrre il più piccolo elenco di denominazioni in modo tale da ottenere il totale ciò include che l'elenco delle denominazioni può essere chiaramente diviso nell'elenco dei pagamenti.

Regole extra

  • Si può presumere che l'elenco delle denominazioni conterrà sempre un 1oppure è possibile aggiungerlo a ciascun elenco.

  • Alcuni input avranno più soluzioni minime. In questi casi è possibile produrre uno dei due.

Questo è quindi le risposte verranno classificate in byte con meno byte migliori.

Casi test

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
All'inizio ho pensato che fosse spam o off-topic o qualcosa del genere ...
Erik the Outgolfer,

1
I paragrafi di @EriktheOutgolfer feriscono così tanto le sfide> _ <
Magic Octopus Urn

2
Penso che dovresti includere almeno un caso di test in cui la richiesta deve essere qualcosa di diverso dalle banconote da un dollaro, come {2,6} {1,2,7} -> {2}.
Arnauld,

@Arnauld Ho aggiunto il tuo caso
Wheat Wizard,

1
(If you are not convinced of this just try to make 29 dollars without making 9)Intendi senza fare 8? O ho frainteso
undergroundmonorail il

Risposte:


5

JavaScript (ES6), 485 476 byte

Va bene ... questo è un mostro. :-(
Ma è un mostro piuttosto veloce che risolve tutti i casi di test quasi all'istante.

Potrei tentare un po 'di golf più avanzato in seguito, ma ci ho già passato troppo tempo.

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

Casi test

Come?

NB: Questo non corrisponde più alla versione corrente, ma è molto più facile da leggere in quel modo.

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

Non ho familiarità con JavaScript, ma puoi ridurre il &&to &e il ||to |?
Taylor Scott,

@TaylorScott Questo è possibile solo a determinate condizioni. Ad esempio, a || bvaluterà bsolo se aè falso, mentre a | beseguirà incondizionatamente un OR bit a bit tra ae b.
Arnauld,

4

Python 2 , 456 455 byte

Estremamente, estremamente, estremamente lento !!!! Dovrebbe funzionare correttamente su tutti gli esempi di input dati abbastanza tempo

Modifica: salvato 1 byte grazie a @Jonathan Frech

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)

Provalo online!

Spiegazione

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
Utilizzo di una funzione piuttosto che input()è un byte più breve .
Jonathan Frech,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.