Bagaimana cara saya meminta uang kepada teller di bank?

35

Saya perlu pergi ke bank dan menarik uang. Saya perlu menarik $ 30, $ 22 untuk membayar teman sekamar saya untuk internet dan $ 8 untuk binatu. Karena tak satu pun dari ini dapat melakukan perubahan, saya perlu $ 30 saya untuk dipecah menjadi dua partisi dari dua ukuran. Itu berarti ketika teller bertanya kepada saya bagaimana saya ingin $ 30 saya, saya harus membuat permintaan. Saya bisa memberi tahu mereka bahwa saya menginginkannya dalam dua puluh, lima, dan lima. Tetapi saya ingin membuat permintaan saya sesederhana mungkin untuk menghindari keharusan mengulang sendiri. Untuk membuat permintaan saya lebih sederhana, saya bisa meminta uang tunai saya mengandung dua puluh dan setidaknya 2 karena 8 tersirat dari total, tetapi lebih baik lagi saya bisa meminta agar salah satu tagihan yang saya terima menjadi tagihan satu dolar (jika Anda tidak yakin dengan hal ini hanya mencoba menghasilkan 29 dolar tanpa menghasilkan 8).

Jadi itu semua bagus dan bagus tapi saya perlu melakukan perhitungan ini setiap kali saya pergi ke bank jadi saya pikir saya akan menulis sebuah program untuk melakukan ini (apakah Anda menulis sebuah program untuk melakukan ini untuk saya).

Program atau fungsi Anda harus mengambil daftar bilangan bulat yang mewakili semua pembayaran yang perlu saya lakukan dan satu set bilangan bulat yang mewakili denominasi tagihan yang tersedia di bank, dan Anda harus menampilkan daftar denominasi terkecil sehingga setiap cara untuk membuat total itu termasuk bahwa daftar denominasi dapat dengan bersih dibagi ke dalam daftar pembayaran.

Aturan ekstra

  • Anda dapat mengasumsikan bahwa daftar denominasi akan selalu berisi 1atau Anda dapat menambahkannya sendiri ke setiap daftar.

  • Beberapa input akan memiliki beberapa solusi minimal. Dalam kasus ini Anda dapat menampilkan salah satu.

Ini adalah sehingga jawaban akan dinilai dalam byte dengan lebih sedikit byte lebih baik.

Uji Kasus

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}
Wisaya Gandum
sumber
22
Pada awalnya saya pikir ini adalah spam atau di luar topik atau sesuatu ...
Erik the Outgolfer
1
Paragraf @EriktheOutgolfer sangat menyakitkan tantangan> _ <
Magic Octopus Mm
2
Saya pikir Anda harus memasukkan setidaknya satu test case di mana permintaan harus berupa sesuatu selain tagihan satu dolar {2,6} {1,2,7} -> {2}.
Arnauld
@Arnauld Saya telah menambahkan kasing Anda
Wheat Wizard
1
(If you are not convinced of this just try to make 29 dollars without making 9)Maksudmu tanpa membuat 8? Atau apakah saya salah paham
undergroundmonorail

Jawaban:

5

JavaScript (ES6), 485 476 byte

Baiklah ... ini monster. :-(
Tapi itu adalah monster yang cukup cepat yang menyelesaikan semua test case secara instan.

Saya mungkin mencoba bermain golf lebih lanjut nanti, tetapi saya sudah menghabiskan terlalu banyak waktu untuk itu.

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

Uji kasus

Bagaimana?

NB: Ini tidak cocok dengan versi saat ini lagi, tetapi jauh lebih mudah dibaca dengan cara itu.

// 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
sumber
Saya tidak terlalu terbiasa dengan javascript, tetapi bisakah Anda mengurangi &&to &dan the ||to |?
Taylor Scott
@TaylorScott Ini hanya mungkin dalam kondisi tertentu. Misalnya, a || bakan mengevaluasi bhanya jika apalsu, sementara a | btanpa syarat akan melakukan bitwise ATAU antara adan b.
Arnauld
4

Python 2 , 456 455 byte

Sangat, sangat, sangat lambat !!!! Harus bekerja dengan benar pada semua contoh input yang diberikan waktu yang cukup

Sunting: Disimpan 1 byte berkat @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)

Cobalah online!

Penjelasan

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
sumber
1
Menggunakan fungsi daripada input()adalah satu byte lebih pendek .
Jonathan Frech