은행에서 은행원에게 돈을 요구하는 방법은 무엇입니까?


35

은행에 가서 돈을 인출해야합니다. 인터넷에 룸메이트를 지불하고 세탁에 8 달러를 지불하려면 30 달러, 22 달러를 인출해야합니다. 이 중 어느 것도 변경할 수 없기 때문에 $ 30을 두 크기의 두 개의 파티션으로 나눌 필요가 있습니다. 이는 텔러가 30 ​​달러를 원하는 방식을 물으면 요청을해야한다는 것을 의미합니다. 나는 그들에게 내가 25, 5, 5로 그것을 원한다고 말할 수 있었다. 그러나 나는 반복하지 않아도되도록 요청을 가능한 한 단순하게 만들고 싶다. 내 요청을 더 간단하게하기 위해 8에 총 20 개의 암시가 있기 때문에 내 현금에 20 개 이상의 최소 2 개가 포함되도록 요청할 수 있지만, 더 좋은 방법은 내가받는 청구서 중 하나가 1 달러짜리 지폐가되도록 요청하는 것입니다. 이것을 확신하지 못하고 단지 8)을 만들지 않고 29 달러를 만들려고합니다.

그래서 그것은 모두 훌륭하고 멋지지만 은행에 갈 때 마다이 계산을 수행해야 하므로이 작업을 수행 할 프로그램을 작성할 것이라고 생각했습니다 (나를 위해 프로그램을 작성 했습니까).

귀하의 프로그램이나 기능은 은행에 사용할 수있는 모든 지불을 나타내는 정수 목록과 청구서 명칭을 나타내는 정수 세트를 가져와야합니다. 해당 교단 목록을 포함하는 지불 목록으로 깔끔하게 나눌 수 있습니다.

추가 규칙

  • 교단 목록에 항상 또는가 포함되어 있다고 가정 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
처음에 나는 ...이 스팸 또는 오프 주제 나 무엇인가라고 생각
에릭 Outgolfer

1
@EriktheOutgolfer 단락 너무 많은 도전을 아프게> _ <
Magic Octopus Urn

2
요청 이 1 달러 지폐 이외의 것이 어야 하는 적어도 하나의 테스트 사례를 포함해야한다고 생각합니다 {2,6} {1,2,7} -> {2}.
Arnauld

@Arnauld 나는 당신의 사건을 추가했습니다
Wheat Wizard

1
(If you are not convinced of this just try to make 29 dollars without making 9)당신은 8을 만들지 않고 의미합니까? 아니면 내가 잘못 이해 했습니까
undergroundmonorail

답변:


5

자바 스크립트 (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])

테스트 사례

어떻게?

주의 : 이것은 현재 버전과 더 이상 일치하지 않지만, 그렇게 읽는 것이 훨씬 쉽습니다.

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

나는 자바 스크립트에 너무 익숙하지 해요,하지만 당신은 줄일 수 &&&하고, |||?
Taylor Scott

@TaylorScott 이것은 특정 조건에서만 가능합니다. 예를 들어, 거짓 인 경우에만 a || b평가 하는 반면 무조건적으로 와 사이의 비트 단위 OR을 수행합니다 . baa | bab
Arnauld

4

파이썬 2 , 456455 바이트

매우, 매우, 매우 느리다! !!! 충분한 시간이 주어진 모든 입력 예제에서 올바르게 작동해야합니다.

편집 : @Jonathan Frech 덕분에 1 바이트가 절약되었습니다 .

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()이다 한 바이트 짧다 .
Jonathan Frech
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.