В текущем проекте люди могут заказывать товары, доставленные к их двери, и выбирать "оплату при доставке" в качестве варианта оплаты. Чтобы убедиться, что у парцевания доставки достаточно изменений, клиентам предлагается ввести сумму, которую они будут платить (например, доставка 48,13, они будут платить 60, - (3 * 20, -)). Теперь, если бы это зависело от меня, я бы сделал это свободным полем, но решительные вышестоящие решения решили, что это должен быть выбор, основанный на доступных номиналах, без предоставления сумм, которые приведут к набору наименований, которые могут быть меньше.
Пример:
denominations = [1,2,5,10,20,50]
price = 78.12
possibilities:
79 (multitude of options),
80 (e.g. 4*20)
90 (e.g. 50+2*20)
100 (2*50)
Это международный, поэтому наименования могут меняться, и алгоритм должен основываться на этом списке.
Ближайший я пришел, который, кажется, работает, это:
for all denominations in reversed order (large=>small)
add ceil(price/denomination) * denomination to possibles
baseprice = floor(price/denomination) * denomination;
for all smaller denominations as subdenomination in reversed order
add baseprice + (ceil((price - baseprice) / subdenomination) * subdenomination) to possibles
end for
end for
remove doubles
sort
Кажется, что это сработало, но это возникло после безумно пытать всевозможные компактные алгоритмы, и я не могу защитить, почему он работает, что может привести к тому, что некоторые крайности/новые страны получат неправильные варианты, и это порождает серьезные количества удвоений.
Поскольку это, вероятно, не новая проблема, и Google et al. не мог предоставить мне ответ, за исключением загрузок страниц, подсчитывающих, как сделать точные изменения, я думал, что спрошу: вы решили эту проблему раньше? Какой алгоритм? Любое доказательство это всегда будет работать?