Як попросити у продавця грошей у банку?


35

Мені потрібно піти в банк і зняти трохи грошей. Мені потрібно зняти 30, 22 долари, щоб заплатити моєму сусіду по кімнаті за Інтернет та 8 доларів за прання. Оскільки жодне з них не може змінити, мені потрібно 30 доларів США, щоб вони були розділені на дві секції двох розмірів. Це означає, що, коли теллер запитує мене, як я хочу, щоб я отримав 30 доларів, мені доведеться зробити запит. Я міг би сказати їм, що хочу цього в двадцять, п'ятьох і п'ятьох. Але я хочу зробити свій запит якомога простішим, щоб уникнути повторення. Щоб спростити запит, я міг би попросити, щоб мої готівки містили двадцять і принаймні 2 гроші, оскільки 8 мається на увазі під загальною сумою, але ще краще, але я міг би просто попросити, щоб одна з купюр, які я отримував, була однодоларовою купюрою (якщо ви не переконані в цьому, просто спробуйте заробити 29 доларів, не роблячи 8).

Отож, це все нормально і безглуздо, але мені потрібно робити цей розрахунок щоразу, коли я йду до банку, щоб я подумав, що я напишу програму для цього (чи ти пишеш програму, щоб це зробити для мене).

Ваша програма або функція повинна містити список цілих чисел, що представляють усі платежі, які мені потрібно здійснити, і набір цілих чисел, що представляють номінали векселів, наявних у банку, і ви повинні вивести найменший список номіналів таким чином, щоб усі способи зробити загальну суму що включає, що список номіналів може бути чітко розділений на перелік платежів.

Додаткові правила

  • Ви можете припустити, що список деномінацій завжди буде містити 1або ви можете додавати його до кожного списку самостійно.

  • Деякі входи матимуть декілька мінімальних рішень. У цих випадках ви можете вивести будь-який.

Це тому відповіді будуть набиратись у байтах, а менша кількість байтів - краща.

Випробування

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
Спочатку я думав, що це спам, або тематика чи щось таке ...
Ерік the Outgolfer

1
Пункти @EriktheOutgolfer так сильно шкодять викликам> _ <
Magic Octopus Urn

2
Я думаю, ви повинні включити принаймні один тестовий випадок, коли запит повинен бути чимось іншим, ніж купюри в один долар {2,6} {1,2,7} -> {2}.
Арнольд

@Arnauld Я додав вашу справу
Пшеничний майстер

1
(If you are not convinced of this just try to make 29 dollars without making 9)Ви маєте на увазі, не роблячи 8? Або я неправильно зрозумів
підземний

Відповіді:


5

JavaScript (ES6), 485 476 байт

Добре ... це чудовисько. :-(
Але це досить швидке чудовисько, яке вирішує всі тестові випадки майже миттєво.

Я можу спробувати трохи просунутий гольф пізніше, але я вже витратив на це занадто багато часу.

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

Тестові справи

Як?

NB: Це вже не відповідає поточній версії, але читати набагато простіше.

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

Я не надто знайомий з javascript, але чи можете ви зменшити значення &&до &і ||до |?
Тейлор Скотт

@TaylorScott Це можливо лише за певних умов. Наприклад, a || bбуде оцінюватися bлише в тому випадку, якщо aце помилково, тоді як a | bбезумовно буде виконувати побітові АБО між aта b.
Арнольд

4

Python 2 , 456 455 байт

Надзвичайно, надзвичайно, надзвичайно повільно !!!! Потрібно правильно працювати над усіма вхідними прикладами, надаючи достатньо часу

Редагувати: Збережено 1 байт завдяки @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)

Спробуйте в Інтернеті!

Пояснення

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
Використання функції, а не input()на один байт коротше .
Джонатан Фрех
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.