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])
テストケース
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])
console.log(JSON.stringify(f([22,8], [1,2,5,10,20,50])))
console.log(JSON.stringify(f([2,1,2], [1,5])))
console.log(JSON.stringify(f([20,10], [1,2,5,10,20,50])))
console.log(JSON.stringify(f([1,1,1,1], [1,2])))
console.log(JSON.stringify(f([20,6], [1,4,5])))
console.log(JSON.stringify(f([2,6], [1,2,7])))
console.log(JSON.stringify(f([22,11], [1,3,30,50])))
console.log(JSON.stringify(f([44,22], [1,3,30,50])))
どうやって?
注意:これは現在のバージョンとは一致していませんが、その方がはるかに読みやすくなっています。
// 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])
)