Bankadan para çağıranı nasıl isterim?


35

Bankaya gidip biraz para çekmem gerekiyor. İnternet için oda arkadaşım ve çamaşır için 8 $ ödemek için 30 $, 22 $ çekmek gerekiyor. Bunların hiçbiri değişmediğinden, iki doların iki bölüme ayrılması için 30 dolarım gerekiyor. Bu, anlatan kişi bana 30 dolarımı nasıl istediğimi sorduğunda, bir ricada bulunacağım anlamına geliyor. Onlara yirmi, beşinci ve beş kişide istediğimi söyleyebilirim. Ancak isteğimi, kendimi tekrarlamak zorunda kalmamak için mümkün olduğunca basitleştirmek istiyorum. Talebimi daha basit hale getirmek için, paramın yirmi en az 2 tane içermesini isteyebilirim çünkü 8 toplamın ima ettiği, ancak daha iyisi, basitçe aldığım faturalardan birinin bir dolarlık banknot olmasını isteyebilirim. Buna ikna olmadınız, sadece 8 yapmadan 29 dolar kazanmaya çalışın).

Yani hepsi güzel ve zordur ancak bankaya her gittiğimde bu hesaplamayı yapmam gerekiyor, bu yüzden bunu yapmak için bir program yazacağımı düşündüm (bunu benim için yapacak bir program yazdınız mı).

Programınız veya işlevin, yapmam gereken tüm ödemeleri temsil eden bir tamsayı listesi ve bankada mevcut olan faturaların değerlerini temsil eden bir tamsayı listesi almalı ve toplamı yapabilmeniz için en küçük miktardaki listeyi çıkarmalısınız. Bu, bu mezhep listesinin açıkça ödemeler listesine bölündüğünü de içerir.

Ekstra kurallar

  • Mezhep listesinin her zaman bir içereceğini varsayabilir 1veya her listeye kendiniz ekleyebilirsiniz.

  • Bazı girdilerin birden fazla minimal çözümü olacaktır. Bu durumlarda ikisinden birini de verebilirsiniz.

Bu olduğundan, cevaplar daha az byte'ın daha iyi olmasıyla byte olarak puanlanacak.

Test Kılıfları

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
İlk başta bunun spam veya konu dışı olduğunu düşündüm ...
Outgolfer Erik

1
@EriktheOutgolfer paragrafları zorluklara çok zarar verdi> _ <
Magic Octopus Urn

2
Sanırım isteğin bir dolarlık banknottan başka bir şey olması gereken en az bir test senaryosunu eklemelisiniz{2,6} {1,2,7} -> {2} .
Arnauld,

@Arnauld'unuzu da ekledim
Buğday Sihirbazı

1
(If you are not convinced of this just try to make 29 dollars without making 9)8 yapmadan mı demek istiyorsun? Yoksa yanlış mı anladım
undergroundmonorail

Yanıtlar:


5

JavaScript (ES6), 485 476 bayt

Tamam ... bu bir canavar. :-(
Ama neredeyse tüm test vakalarını anında çözen oldukça hızlı bir canavar.

Daha sonra biraz daha ileri golf oynamaya çalışabilirim, ancak çok fazla zaman harcadım.

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

Test durumları

Nasıl?

Not: Bu, artık geçerli sürümle eşleşmiyor, ancak bu şekilde okunması çok daha kolay.

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

Ben javascript ile çok aşina değilim ama azaltabilir &&için &ve ||hiç |?
Taylor Scott

@TaylorScott Bu, yalnızca belirli koşullar altında mümkündür. Örneğin, a || bdeğerlendirecek byalnızca aiken, falsy olduğu a | bkoşulsuz arasındaki YA üzerinde ikilik gerçekleştirecek ave b.
Arnauld

4

Python 2 , 456 455 bayt

Son derece, son derece, son derece yavaş !!!! Yeterli zaman verilen tüm girdi örnekleri üzerinde doğru çalışmalı

Düzenleme: @Jonathan Frech sayesinde 1 bayt kaydedildi

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)

Çevrimiçi deneyin!

açıklama

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
Bir fonksiyonu kullanmak yerine input()ise bir byte daha kısa .
Jonathan Frech
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.