Comment demander de l'argent à un caissier à la banque?

35

Je dois aller à la banque et retirer de l'argent. J'ai besoin de retirer 30 dollars, 22 dollars pour payer mon coloc pour Internet et 8 dollars pour le linge. Comme aucun de ceux-ci ne peut rendre la monnaie, j'ai besoin que mes 30 dollars soient divisés en deux partitions des deux tailles. Cela signifie que lorsque le caissier me demande comment je veux mes 30 $, je vais devoir faire une demande. Je pourrais leur dire que je le veux dans vingt, cinq et cinq. Mais je veux que ma demande soit aussi simple que possible afin d'éviter de devoir me répéter. Pour simplifier ma demande, je pourrais demander que mon argent en contienne 20 et au moins 2 parce que le total 8 est implicite, mais mieux encore, je pourrais simplement demander que l’une des factures que je reçoive soit un dollar ne sont pas convaincus de cela, essayez simplement de gagner 29 dollars sans en faire 8).

Donc tout va bien, mais je dois faire ce calcul chaque fois que je vais à la banque, alors je pensais écrire un programme pour le faire (avez-vous écrit un programme pour le faire pour moi).

Votre programme ou fonction doit contenir une liste d’entiers représentant tous les paiements que je dois effectuer et un ensemble d’entiers représentant les valeurs nominales des factures disponibles à la banque. Vous devez générer la plus petite liste de valeurs nominales de sorte que le total cela inclut cette liste de dénominations peut être proprement divisée en la liste de paiements.

Règles supplémentaires

  • Vous pouvez supposer que la liste des dénominations contiendra toujours un 1ou vous pourrez l’ajouter vous-même à chaque liste.

  • Certaines entrées auront plusieurs solutions minimales. Dans ces cas, vous pouvez sortir l’un ou l’autre.

C'est du donc les réponses seront notées en octets, moins d'octets étant meilleurs

Cas de 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}
Assistant de blé
la source
22
Au début, je pensais que c'était du spam ou hors sujet ou quelque chose comme ça ...
Erik the Outgolfer 21/09/17
1
Les paragraphes @EriktheOutgolfer font tellement mal aux défis> _ <
Urne Octopus magique
2
Je pense que vous devriez inclure au moins un cas test où la demande doit être autre que des billets d'un dollar, comme {2,6} {1,2,7} -> {2}.
Arnauld
@Arnauld J'ai ajouté votre cas
Wheat Wizard
1
(If you are not convinced of this just try to make 29 dollars without making 9)Vous voulez dire sans faire 8? Ou ai-je mal compris
undergroundmonorail

Réponses:

5

JavaScript (ES6), 485 476 octets

Bon ... c'est un monstre. :-(
Mais c'est un monstre assez rapide qui résout tous les cas de test presque instantanément.

J'essaierai peut-être un peu plus de golf plus tard, mais j'ai déjà passé beaucoup trop de temps dessus.

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

Cas de test

Comment?

NB: Cela ne correspond plus à la version actuelle, mais est beaucoup plus facile à lire de cette façon.

// 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
la source
Je ne suis pas trop familier avec javascript, mais pouvez-vous réduire le &&to &et le ||to |?
Taylor Scott
@TaylorScott Ceci n'est possible que sous certaines conditions. Par exemple, a || bn'évaluera bque si aest falsy, alors a | bqu'il effectuera inconditionnellement un OU au niveau du bit entre aet b.
Arnauld
4

Python 2 , 456 455 octets

Extrêmement, extrêmement, extrêmement lent !!!! Devrait fonctionner correctement sur tous les exemples d'entrée donnés suffisamment de temps

Edit: 1 octet enregistré grâce à @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)

Essayez-le en ligne!

Explication

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
la source
1
En utilisant une fonction plutôt input()est un octet plus courte .
Jonathan Frech