Как я могу попросить у кассира деньги в банке?


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
Сначала я подумал, что это спам, или не по теме, или что-то в этом роде ...
Эрик Аутгольфер,

1
@EriktheOutgolfer параграфы так больно бросают вызов> _ <
Волшебная урна осьминога

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

@Arnauld Я добавил твое дело
Wheat Wizard

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.