Como peço dinheiro a um caixa no banco?


35

Eu preciso ir ao banco e sacar algum dinheiro. Preciso retirar US $ 30, US $ 22 para pagar à minha colega de quarto pela internet e US $ 8 pela lavanderia. Como nenhum deles pode fazer alterações, preciso que meus US $ 30 sejam divididos em duas partições dos dois tamanhos. Isso significa que, quando o caixa me perguntar como quero meus US $ 30, terei que fazer uma solicitação. Eu poderia dizer a eles que eu quero isso em vinte, cinco e cinco. Mas quero tornar minha solicitação o mais simples possível, para evitar ter que me repetir. Para simplificar minha solicitação, eu poderia pedir que meu dinheiro contenha vinte e pelo menos 2, porque o 8 está implícito no total, mas, melhor ainda, eu poderia simplesmente solicitar que uma das contas recebidas seja uma nota de um dólar (se você não está convencido disso, tente ganhar 29 dólares sem fazer 8).

Então está tudo bem e elegante, mas preciso fazer esse cálculo toda vez que vou ao banco, então pensei em escrever um programa para fazer isso (você escreveu um programa para fazer isso por mim).

Seu programa ou função deve ter uma lista de números inteiros que representam todos os pagamentos que preciso fazer e um conjunto de números inteiros que representam as denominações de notas disponíveis no banco, e você deve exibir a menor lista de denominações, de modo que todas as maneiras de fazer o total isso inclui que a lista de denominações pode ser claramente dividida na lista de pagamentos.

Regras extras

  • Você pode supor que a lista de denominação sempre contenha um 1ou você pode adicioná-la a cada lista.

  • Algumas entradas terão várias soluções mínimas. Nesses casos, você pode gerar um dos dois.

Isso é então as respostas serão pontuadas em bytes, com menos bytes sendo melhores.

Casos de teste

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
No começo eu pensei que esta era spam ou off-topic ou algo assim ...
Erik o Outgolfer

11
@EriktheOutgolfer parágrafos machucam tanto os desafios> _ <
Magic Octopus Urn

2
Eu acho que você deve incluir pelo menos um caso de teste em que a solicitação deva ser algo diferente de notas de um dólar, como {2,6} {1,2,7} -> {2}.
Arnauld

@Arnauld Adicionei seu caso
Wheat Wizard

11
(If you are not convinced of this just try to make 29 dollars without making 9)Você quer dizer sem fazer 8? Ou Eu entendi mal
undergroundmonorail

Respostas:


5

JavaScript (ES6), 485 476 bytes

Tudo bem ... isso é um monstro. :-(
Mas é um monstro bastante rápido que resolve todos os casos de teste quase instantaneamente.

Posso tentar um pouco de golfe mais avançado mais tarde, mas já gastei muito tempo nele.

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

Casos de teste

Quão?

NB: Isso não corresponde mais à versão atual, mas é muito mais fácil de ler dessa maneira.

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

Não estou muito familiarizado com javascript, mas você pode reduzir o &&para &e o ||para |?
Taylor Scott

@TaylorScott Isso só é possível sob certas condições. Por exemplo, a || bavaliará bapenas se afor falso, enquanto a | bexecutará incondicionalmente um OR bit a bit entre ae b.
Arnauld 22/09

4

Python 2 , 456 455 bytes

Extremamente, extremamente, extremamente lento !!!! Deve funcionar corretamente em todos os exemplos de entrada, com tempo suficiente

Edit: Salvo 1 byte graças a @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)

Experimente online!

Explicação

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)

11
Utilizando uma função e não input()é um byte mais curto .
Jonathan Frech 22/09
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.