Алгоритм разложения суммы на неизвестные члены

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Доброго времени суток, ув.тов. программисты.

Большая просьба помочь в оптимизации алгоритма разложения суммы на составляющие члены.

Или иначе говоря — задачи выдачи сдачи, только начальные условия заранее не известны,

такие как: купюры, их кратность друг другу, разлогаемая сумма и т.д.

Дано: массив denom (купюры, могут быть от 0.001 до 99999999999999), amount (данная сумма к разложению).

Найти: ответить — разлогается ли сумма + если нет, то ближайшая разлогаемая сумма, больше заданной.

Грубо говоря — задача решена, но с учётом того, что её используют на javascript

время выполнения иногда большое очень и броузер прекращяет выполнять скрипт.

[!] Проблема в том, что когда купюры равны 10000 (к примеру!), а сумма 999999999, то итераций получается очень много и как их уменьшить я не знаю.

Суть алгоритма в том, что мы получаем массив dyn с суммами, которые мы можем разложить.

В цикле проходим по массиву, если его значени 1, то и прибавив к этому индексу любую купюру, мы тоже получим сумму.

Привер:

у нас есть 2, 3, 5 купюры, для суммы 7:

dyn [0] = 1 (т.е. сумму нуль мы можем разложить)

dyn [0+2] = 1 (а в цикле: если if (dyn [i] == 1) dyn [i+новая купюра] = 1)

dyn [2+2] = 1

dyn [4+2] = 1

dyn [6+2] = 1 (больше amount — оставляем как альтернативное решение)

dyn [0+3] = 1

dyn [2+3] = 1

dyn [3+3] = 1

dyn [5+3] = 1

dyn [0+5] = 1

dyn [2+5] = 1 (стоп!)

Подскажите пож-та, заранее благодарен.

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

2Аноним, скажи пож-та откуда этот вывод? Есть такое правило?

Идея № 1: Если у нас есть только две a1 и a2 купюры и они взаимопросты, то можно получить всё, что больше (a1*a2-a1-a2) = (a1−1) * (a2−1) — 1.

Это, по-моему, уже интересно. Нужно найти две взаимнопростых купюры, минимизирующих (a1−1) * (a2−1). Если мы нашли и требуемая сумма не меньше — она разложима

2CVA: По-моему, как раз для реальных валют задачи получаются простые. Вы посмотрите свою статистику. После сокращения нулей обычно остаётся купюра достоинством 1, в худшем случае пара (2 и 5). Это же очень простые случаи.

Добавление мелочи задачу почти наверняка упрощает! Ведь если есть «купюра» в 0.01, то все остальные можно выкинуть, т.к. они точно делятся на 0.01 и вообще выдаётся всё, что кратно 0.01. Монеты реальных стран почти всегда «делят» целую купюру, т.е. упрощают задачу. Мне известна только одна «плохая» монета, которая встречалась (а может и до сих пор встречается где-то): 15 копеек. Тут нужно смотреть и всё равно почти наверняка можно оставить две самые мелкие монеты (если одна из них 15) и для больших сумм пользоваться указанным выше правилом про два номинала. Ну, а маленькие номиналы банально перебираются.

2Аноним спасибо, как раз бегло изучил эту книгу с подачи hellip.
Это реальный проект, люди хотят знать, вот просят 157085 тугриков замбии, а мелочь они не хранят — и верно ли это, что можно выдать эти бабки бумажными купюрами.
Тока под это дело они навбивали купюры номиналом 0.01 к примеру — думаю дальше будет тока круче ((
2hellip благодарю.

Спасибо большое всем за помощь. Успехов!

2CVA: Интересно, это реальный проект, или исследовательская задача? Просто если проект реальный, может стоит поговорить с заказчиком. Как я понимаю, в реальных валютах совсем плохих случаев не бывает.

Ваш же последний пример, кстати, решается моментально. Займусь самоцитированием:

Идея № 1: Если у нас есть только две a1 и a2 купюры и они взаимопросты, то можно получить всё, что больше (a1*a2-a1-a2) = (a1−1) * (a2−1) — 1.

(20 — 1) * (71 −1) = 1330 < 2110, т.е. сумма разложима.

Так что если очертить круг «реальных» задач, то, я думаю, большинство из них решается очень быстро. А если нужно уметь решать совсём всё, то тут, конечно, не судьба. Хотя вот это может послужить утешением: http://max.cs.kzoo.edu/~kschultz/CS510/ClassPresentations/NPCartoons.html

М-да? Тогда я только могу подтвердить свое мнение, сформировавшееся при первом взгляде на эту задачу. Косяки неустранимы в принципе при нынешнем уровне развития теории алгоритмов: (

Вона, у Бентли похожая по сложности задача (Entscheidungsproblem, если быть точным) в практикуме к «Жемчужинам программирования». В конце книги есть подсказки к практикуму. Против номера этой задачи стоит смайлик и написано:

Если вы решили эту задачу, вам нужно немедленно звонить в комитет по присуждению премии Филдса.

см. en.wikipedia.org/...Negative_answer

Требуют универсальный алгоритм, т.е. если вбить могут что угодно.
пример:
купюры 1000, 2000, 3550.
amount 105500.
НОД = 50
сокращяем, получаем (удаляем кратные, т.е. 40):
20 71
2110

теперь:


цикл (banknote = 1; banknote <=2; banknote++) // 2 итерации -  по последнюю купюру
цикл (i=0; i<2110+20;i++) (т.е. то что нам надо =2110, только ищем ещё одно заведомо правильное решение, если 2110 не разложится)
{
   если answer[i] == 1 то
        answer[ i+купюры[banknote] ] = 1

если answer[2110] == 1
     стоп;
}

примерно так всё происходит.

Можно придумать разные обходы и подходы — пробовал много чего, но каждый раз появляется пример/подводный камень, из-за которого вылазиет косяк.

точно, а мы ужо испугались, NP-полнота, вычислимость по Чёрчу-Тьюрингу..., а оно вон как просто.

2Kolo-67

Цитата из первого поста (выделение моё):

Грубо говоря — задача решена, но с учётом того, что её используют на javascript время выполнения иногда большое очень и броузер прекращяет выполнять скрипт.

по-моему, содержит ответ на вопрос.

а все таки где производится вычисление? на клиенте в броузере или на сервере?

если на серевере то при нормальном языке реализации при таких данных (количество купюр в каждой стране очень невелико) вычисления должны проходить достаточно быстро даже без особой оптимизации

2CVA: Я правильно понимаю, что идея такая: человек вводит сумму и название валюты, а мы смотрим, можно ли её выдать купюрами только этой валюты?
Например, правда ли, что список валют и купюр в них заранее известен? Тогда первое, что можно сделать это отфильтровать сами купюры по разложимости на более мелкими. Навскидку во всех страннах в этом списке остаётся либо одна самая мелкая, на которую всё делится, либо две мелких купюры (2 и 5 или 20 и 50). А для этих случаев ответ для крупных сумм просто известен и указывался выше в обсуждении. Если это не помогает, можно указать валюту и сумму, которая считается долго?

Если я не правильно понял условие, тогда уточните, пожалуйста.

denom [Argentina] [1] = 100.00;
denom [Argentina] [2] = 50.00;
denom [Argentina] [3] = 20.00;
denom [Argentina] [4] = 10.00;
denom [Argentina] [5] = 5.00;
denom [Argentina] [6] = 2.00;
denom [Australia] [1] = 100.00;
denom [Australia] [2] = 50.00;
denom [Australia] [3] = 20.00;
denom [Australia] [4] = 10.00;
denom [Australia] [5] = 5.00;
denom [Bahamas] [1] = 100.00;
denom [Bahamas] [2] = 50.00;
denom [Bahamas] [3] = 20.00;
denom [Bahamas] [4] = 10.00;
denom [Bahamas] [5] = 5.00;
denom [Bahamas] [6] = 3.00;
denom [Bahamas] [7] = 1.00;
denom [Barbados] [1] = 100.00;
denom [Barbados] [2] = 50.00;
denom [Barbados] [3] = 20.00;
denom [Barbados] [4] = 10.00;
denom [Barbados] [5] = 5.00;
denom [Barbados] [6] = 2.00;
denom [Belize] [1] = 100.00;
denom [Belize] [2] = 50.00;
denom [Belize] [3] = 20.00;
denom [Belize] [4] = 10.00;
denom [Belize] [5] = 5.00;
denom [Belize] [6] = 2.00;
denom [Bermuda] [1] = 100.00;
denom [Bermuda] [2] = 50.00;
denom [Bermuda] [3] = 20.00;
denom [Bermuda] [4] = 10.00;
denom [Bermuda] [5] = 5.00;
denom [Bermuda] [6] = 2.00;
denom [Brazil] [1] = 100.00;
denom [Brazil] [2] = 50.00;
denom [Brazil] [3] = 20.00;
denom [Brazil] [4] = 10.00;
denom [Brazil] [5] = 5.00;
denom [Brazil] [6] = 2.00;
denom [Brazil] [7] = 1.00;
denom [Canada] [1] = 1000.00;
denom [Canada] [2] = 100.00;
denom [Canada] [3] = 50.00;
denom [Canada] [4] = 20.00;
denom [Canada] [5] = 10.00;
denom [Canada] [6] = 5.00;
denom [Cayman Islands] [1] = 100.00;
denom [Cayman Islands] [2] = 50.00;
denom [Cayman Islands] [3] = 25.00;
denom [Cayman Islands] [4] = 10.00;
denom [Cayman Islands] [5] = 5.00;
denom [Cayman Islands] [6] = 1.00;
denom [Chile] [1] = 20000.00;
denom [Chile] [2] = 10000.00;
denom [Chile] [3] = 5000.00;
denom [Chile] [4] = 2000.00;
denom [Chile] [5] = 1000.00;
denom [China] [1] = 100.00;
denom [China] [2] = 50.00;
denom [China] [3] = 20.00;
denom [China] [4] = 10.00;
denom [China] [5] = 5.00;
denom [China] [6] = 1.00;
denom [Colombia] [1] = 50000.00;
denom [Colombia] [2] = 20000.00;
denom [Colombia] [3] = 10000.00;
denom [Colombia] [4] = 5000.00;
denom [Colombia] [5] = 2000.00;
denom [Colombia] [6] = 1000.00;
denom [Costa Rica] [1] = 10000.00;
denom [Costa Rica] [2] = 5000.00;
denom [Costa Rica] [3] = 2000.00;
denom [Costa Rica] [4] = 1000.00;
denom [Cyprus] [1] = 20.00;
denom [Cyprus] [2] = 10.00;
denom [Cyprus] [3] = 5.00;
denom [Cyprus] [4] = 1.00;
denom [Czech Republic] [1] = 5000.00;
denom [Czech Republic] [2] = 2000.00;
denom [Czech Republic] [3] = 1000.00;
denom [Czech Republic] [4] = 500.00;
denom [Czech Republic] [5] = 200.00;
denom [Czech Republic] [6] = 100.00;
denom [Czech Republic] [7] = 50.00;
denom [Denmark] [1] = 1000.00;
denom [Denmark] [2] = 500.00;
denom [Denmark] [3] = 200.00;
denom [Denmark] [4] = 100.00;
denom [Denmark] [5] = 50.00;
denom [Dominican Republic] [1] = 2000.00;
denom [Dominican Republic] [2] = 1000.00;
denom [Dominican Republic] [3] = 500.00;
denom [Dominican Republic] [4] = 200.00;
denom [Dominican Republic] [5] = 100.00;
denom [Dominican Republic] [6] = 50.00;
denom [Dominican Republic] [7] = 20.00;
denom [Dominican Republic] [8] = 10.00;
denom [Eastern Caribbean] [1] = 100.00;
denom [Eastern Caribbean] [2] = 50.00;
denom [Eastern Caribbean] [3] = 20.00;
denom [Eastern Caribbean] [4] = 10.00;
denom [Eastern Caribbean] [5] = 5.00;
denom [Egypt] [1] = 200.00;
denom [Egypt] [2] = 100.00;
denom [Egypt] [3] = 50.00;
denom [Egypt] [4] = 20.00;
denom [Egypt] [5] = 10.00;
denom [Egypt] [6] = 5.00;
denom [Egypt] [7] = 1.00;
denom [European Central Bank] [1] = 500.00;
denom [European Central Bank] [2] = 200.00;
denom [European Central Bank] [3] = 100.00;
denom [European Central Bank] [4] = 50.00;
denom [European Central Bank] [5] = 20.00;
denom [European Central Bank] [6] = 10.00;
denom [European Central Bank] [7] = 5.00;
denom [Fiji] [1] = 50.00;
denom [Fiji] [2] = 20.00;
denom [Fiji] [3] = 10.00;
denom [Fiji] [4] = 5.00;
denom [Fiji] [5] = 2.00;
denom [Guatemala] [1] = 100.00;
denom [Guatemala] [2] = 50.00;
denom [Guatemala] [3] = 20.00;
denom [Guatemala] [4] = 10.00;
denom [Guatemala] [5] = 5.00;
denom [Honduras] [1] = 500.00;
denom [Honduras] [2] = 100.00;
denom [Honduras] [3] = 50.00;
denom [Honduras] [4] = 20.00;
denom [Honduras] [5] = 10.00;
denom [Honduras] [6] = 5.00;
denom [Honduras] [7] = 1.00;
denom [Hong Kong] [1] = 1000.00;
denom [Hong Kong] [2] = 500.00;
denom [Hong Kong] [3] = 100.00;
denom [Hong Kong] [4] = 50.00;
denom [Hong Kong] [5] = 20.00;
denom [Hong Kong] [6] = 10.00;
denom [Hungary] [1] = 20000.00;
denom [Hungary] [2] = 10000.00;
denom [Hungary] [3] = 5000.00;
denom [Hungary] [4] = 2000.00;
denom [Hungary] [5] = 1000.00;
denom [Hungary] [6] = 500.00;
denom [Hungary] [7] = 200.00;
denom [Iceland] [1] = 5000.00;
denom [Iceland] [2] = 2000.00;
denom [Iceland] [3] = 1000.00;
denom [Iceland] [4] = 500.00;
denom [India] [1] = 1000.00;
denom [India] [2] = 500.00;
denom [India] [3] = 100.00;
denom [India] [4] = 50.00;
denom [India] [5] = 20.00;
denom [India] [6] = 10.00;
denom [India] [7] = 5.00;
denom [Indonesia] [1] = 1000000.00;
denom [Indonesia] [2] = 50000.00;
denom [Indonesia] [3] = 20000.00;
denom [Indonesia] [4] = 10000.00;
denom [Indonesia] [5] = 5000.00;
denom [Indonesia] [6] = 1000.00;
denom [Iraq] [1] = 25000.00;
denom [Iraq] [2] = 10000.00;
denom [Iraq] [3] = 5000.00;
denom [Iraq] [4] = 1000.00;
denom [Iraq] [5] = 500.00;
denom [Iraq] [6] = 250.00;
denom [Iraq] [7] = 50.00;
denom [Israel] [1] = 200.00;
denom [Israel] [2] = 100.00;
denom [Israel] [3] = 50.00;
denom [Israel] [4] = 20.00;
denom [Israel] [5] = 10.00;
denom [Jamaica] [1] = 1000.00;
denom [Jamaica] [2] = 500.00;
denom [Jamaica] [3] = 50.00;
denom [Jamaica] [4] = 20.00;
denom [Japan] [1] = 10000.00;
denom [Japan] [2] = 5000.00;
denom [Japan] [3] = 2000.00;
denom [Japan] [4] = 1000.00;
denom [Jordan] [1] = 50.00;
denom [Jordan] [2] = 20.00;
denom [Jordan] [3] = 10.00;
denom [Jordan] [4] = 5.00;
denom [Jordan] [5] = 1.00;
denom [Korea] [1] = 10000.00;
denom [Korea] [2] = 5000.00;
denom [Korea] [3] = 1000.00;
denom [Kuwait] [1] = 20.00;
denom [Kuwait] [2] = 10.00;
denom [Kuwait] [3] = 5.00;
denom [Kuwait] [4] = 1.00;
denom [Kuwait] [5] = 0.25;
denom [Kuwait] [6] = 0.50;
denom [Malaysia] [1] = 100.00;
denom [Malaysia] [2] = 50.00;
denom [Malaysia] [3] = 10.00;
denom [Malaysia] [4] = 5.00;
denom [Malaysia] [5] = 2.00;
denom [Malaysia] [6] = 1.00;
denom [Malta] [1] = 20.00;
denom [Malta] [2] = 10.00;
denom [Malta] [3] = 5.00;
denom [Malta] [4] = 2.00;
denom [Mexico] [1] = 1000.00;
denom [Mexico] [2] = 500.00;
denom [Mexico] [3] = 200.00;
denom [Mexico] [4] = 100.00;
denom [Mexico] [5] = 50.00;
denom [Mexico] [6] = 20.00;
denom [Morocco] [1] = 200.00;
denom [Morocco] [2] = 100.00;
denom [Morocco] [3] = 50.00;
denom [Morocco] [4] = 20.00;
denom [Morocco] [5] = 10.00;
denom [Netherlands Antilles] [1] = 250.00;
denom [Netherlands Antilles] [2] = 100.00;
denom [Netherlands Antilles] [3] = 50.00;
denom [Netherlands Antilles] [4] = 25.00;
denom [Netherlands Antilles] [5] = 10.00;
denom [Netherlands Antilles] [6] = 5.00;
denom [New Zealand] [1] = 100.00;
denom [New Zealand] [2] = 50.00;
denom [New Zealand] [3] = 20.00;
denom [New Zealand] [4] = 10.00;
denom [New Zealand] [5] = 5.00;
denom [Northern Ireland] [1] = 100.00;
denom [Northern Ireland] [2] = 50.00;
denom [Northern Ireland] [3] = 20.00;
denom [Northern Ireland] [4] = 10.00;
denom [Northern Ireland] [5] = 5.00;
denom [Norway] [1] = 1000.00;
denom [Norway] [2] = 500.00;
denom [Norway] [3] = 200.00;
denom [Norway] [4] = 100.00;
denom [Norway] [5] = 50.00;
denom [Oman] [1] = 50.00;
denom [Oman] [2] = 20.00;
denom [Oman] [3] = 10.00;
denom [Oman] [4] = 5.00;
denom [Oman] [5] = 1.00;
denom [Oman] [6] = 0.25;
denom [Oman] [7] = 0.50;
denom [Pakistan] [1] = 5000.00;
denom [Pakistan] [2] = 1000.00;
denom [Pakistan] [3] = 500.00;
denom [Pakistan] [4] = 100.00;
denom [Pakistan] [5] = 50.00;
denom [Pakistan] [6] = 20.00;
denom [Pakistan] [7] = 10.00;
denom [Pakistan] [8] = 5.00;
denom [Peru] [1] = 200.00;
denom [Peru] [2] = 100.00;
denom [Peru] [3] = 50.00;
denom [Peru] [4] = 20.00;
denom [Peru] [5] = 10.00;
denom [Philippines] [1] = 1000.00;
denom [Philippines] [2] = 500.00;
denom [Philippines] [3] = 200.00;
denom [Philippines] [4] = 100.00;
denom [Philippines] [5] = 50.00;
denom [Philippines] [6] = 20.00;
denom [Philippines] [7] = 10.00;
denom [Poland] [1] = 200.00;
denom [Poland] [2] = 100.00;
denom [Poland] [3] = 50.00;
denom [Poland] [4] = 20.00;
denom [Poland] [5] = 10.00;
denom [Qatar] [1] = 500.00;
denom [Qatar] [2] = 100.00;
denom [Qatar] [3] = 50.00;
denom [Qatar] [4] = 10.00;
denom [Qatar] [5] = 5.00;
denom [Qatar] [6] = 1.00;
denom [Russian Federation] [1] = 5000.00;
denom [Russian Federation] [2] = 1000.00;
denom [Russian Federation] [3] = 500.00;
denom [Russian Federation] [4] = 100.00;
denom [Russian Federation] [5] = 50.00;
denom [Russian Federation] [6] = 10.00;
denom [Saudi Arabia] [1] = 500.00;
denom [Saudi Arabia] [2] = 200.00;
denom [Saudi Arabia] [3] = 100.00;
denom [Saudi Arabia] [4] = 50.00;
denom [Saudi Arabia] [5] = 20.00;
denom [Saudi Arabia] [6] = 10.00;
denom [Saudi Arabia] [7] = 5.00;
denom [Saudi Arabia] [8] = 1.00;
denom [Scotland] [1] = 100.00;
denom [Scotland] [2] = 50.00;
denom [Scotland] [3] = 20.00;
denom [Scotland] [4] = 10.00;
denom [Scotland] [5] = 5.00;
denom [Scotland] [6] = 1.00;
denom [Singapore] [1] = 1000.00;
denom [Singapore] [2] = 100.00;
denom [Singapore] [3] = 50.00;
denom [Singapore] [4] = 10.00;
denom [Singapore] [5] = 5.00;
denom [Singapore] [6] = 2.00;
denom [South Africa] [1] = 200.00;
denom [South Africa] [2] = 100.00;
denom [South Africa] [3] = 50.00;
denom [South Africa] [4] = 20.00;
denom [South Africa] [5] = 10.00;
denom [Sweden] [1] = 1000.00;
denom [Sweden] [2] = 500.00;
denom [Sweden] [3] = 100.00;
denom [Sweden] [4] = 50.00;
denom [Sweden] [5] = 20.00;
denom [Switzerland] [1] = 1000.00;
denom [Switzerland] [2] = 200.00;
denom [Switzerland] [3] = 100.00;
denom [Switzerland] [4] = 50.00;
denom [Switzerland] [5] = 20.00;
denom [Switzerland] [6] = 10.00;
denom [Tahiti] [1] = 10000.00;
denom [Tahiti] [2] = 5000.00;
denom [Tahiti] [3] = 1000.00;
denom [Tahiti] [4] = 500.00;
denom [Taiwan] [1] = 2000.00;
denom [Taiwan] [2] = 1000.00;
denom [Taiwan] [3] = 500.00;
denom [Taiwan] [4] = 200.00;
denom [Taiwan] [5] = 100.00;
denom [Thailand] [1] = 1000.00;
denom [Thailand] [2] = 500.00;
denom [Thailand] [3] = 100.00;
denom [Thailand] [4] = 50.00;
denom [Thailand] [5] = 20.00;
denom [Trinidad and Tobago] [1] = 100.00;
denom [Trinidad and Tobago] [2] = 20.00;
denom [Trinidad and Tobago] [3] = 10.00;
denom [Trinidad and Tobago] [4] = 5.00;
denom [Trinidad and Tobago] [5] = 1.00;
denom [Turkey] [1] = 200.00;
denom [Turkey] [2] = 100.00;
denom [Turkey] [3] = 50.00;
denom [Turkey] [4] = 20.00;
denom [Turkey] [5] = 10.00;
denom [Turkey] [6] = 5.00;
denom [Turkey] [7] = 1.00;
denom [United Arab Emirates] [1] = 1000.00;
denom [United Arab Emirates] [2] = 500.00;
denom [United Arab Emirates] [3] = 200.00;
denom [United Arab Emirates] [4] = 100.00;
denom [United Arab Emirates] [5] = 50.00;
denom [United Arab Emirates] [6] = 20.00;
denom [United Arab Emirates] [7] = 10.00;
denom [United Arab Emirates] [8] = 5.00;
denom [United Kingdom] [1] = 50.00;
denom [United Kingdom] [2] = 20.00;
denom [United Kingdom] [3] = 10.00;
denom [United Kingdom] [4] = 5.00;
denom [United States of America] [1] = 100.00;
denom [United States of America] [2] = 50.00;
denom [United States of America] [3] = 20.00;
denom [United States of America] [4] = 10.00;
denom [United States of America] [5] = 5.00;
denom [United States of America] [6] = 2.00;
denom [United States of America] [7] = 1.00;
denom [Vietnam] [1] = 500000.00;
denom [Vietnam] [2] = 200000.00;
denom [Vietnam] [3] = 100000.00;
denom [Vietnam] [4] = 50000.00;
denom [Vietnam] [5] = 20000.00;
denom [Vietnam] [6] = 10000.00;
denom [Disney] [1] = 10.00;
denom [Disney] [2] = 5.00;
denom [Disney] [3] = 1.00;
denom [Jack Nicklaus 5] [1] = 1.00;
denom [Faxes] [1] = 1.00;
denom [Italian Legacy Currency] [1] = 500000.00;
denom [Italian Legacy Currency] [2] = 100000.00;
denom [Italian Legacy Currency] [3] = 50000.00;
denom [Italian Legacy Currency] [4] = 5000.00;
denom [Italian Legacy Currency] [5] = 2000.00;
denom [Italian Legacy Currency] [6] = 1000.00;
denom [Spain Legacy Currency] [1] = 10000.00;
denom [Spain Legacy Currency] [2] = 5000.00;
denom [Spain Legacy Currency] [3] = 2000.00;
denom [Spain Legacy Currency] [4] = 1000.00;
denom [Finland Legacy Currency] [1] = 1000.00;
denom [Finland Legacy Currency] [2] = 500.00;
denom [Finland Legacy Currency] [3] = 100.00;
denom [Finland Legacy Currency] [4] = 50.00;
denom [Finland Legacy Currency] [5] = 20.00;
denom [Belgium Legacy Currency] [1] = 200.00;
denom [Belgium Legacy Currency] [2] = 100.00;
denom [France Legacy Currency] [1] = 50.00;
denom [France Legacy Currency] [2] = 20.00;
denom [German Legacy Currency] [1] = 1000.00;
denom [German Legacy Currency] [2] = 500.00;
denom [German Legacy Currency] [3] = 200.00;
denom [German Legacy Currency] [4] = 100.00;
denom [German Legacy Currency] [5] = 50.00;
denom [German Legacy Currency] [6] = 20.00;
denom [Austria] [1] = 5000.00;
denom [Austria] [2] = 1000.00;
denom [Austria] [3] = 500.00;
denom [Austria] [4] = 100.00;
denom [Austria] [5] = 50.00;
denom [Austria] [6] = 20.00;
denom [Estonia] [1] = 500.00;
denom [Estonia] [2] = 100.00;
denom [Estonia] [3] = 50.00;
denom [Estonia] [4] = 25.00;
denom [Estonia] [5] = 10.00;
denom [Estonia] [6] = 5.00;
denom [Estonia] [7] = 2.00;
denom [Lithuania] [1] = 500.00;
denom [Lithuania] [2] = 200.00;
denom [Lithuania] [3] = 100.00;
denom [Lithuania] [4] = 50.00;
denom [Lithuania] [5] = 20.00;
denom [Lithuania] [6] = 10.00;
denom [Latvia] [1] = 500.00;
denom [Latvia] [2] = 100.00;
denom [Latvia] [3] = 50.00;
denom [Latvia] [4] = 20.00;
denom [Latvia] [5] = 10.00;
denom [Latvia] [6] = 5.00;
denom [Bulgaria] [1] = 50.00;
denom [Bulgaria] [2] = 20.00;
denom [Bulgaria] [3] = 10.00;
denom [Bulgaria] [4] = 5.00;
denom [Bulgaria] [5] = 2.00;
denom [Croatia] [1] = 1000.00;
denom [Croatia] [2] = 500.00;
denom [Croatia] [3] = 200.00;
denom [Croatia] [4] = 100.00;
denom [Croatia] [5] = 50.00;
denom [Croatia] [6] = 20.00;
denom [Croatia] [7] = 10.00;
denom [Hotel Room] [1] = 1.00;

denom [MoneyGram OUT] [1] = 0.01;

Говоря «топорно»: не хотят возиться с бумажками, следовательно нужно проверить какую они вбили сумму, т.е. выдаётся ли она целым количеством купюр.
2Аноним статистика есть, данных много, вкратце:
макс.номинал купюры 1000000.00;
мин.номинал купюры 0.01;
Но этим не ограничены условия, т.е. могут создать ещё дальше...
2hellip спасибо за ответ

2kolo-67 мн-во R можно опустить — для меня это не важно (см.выше), спасибо.

2cva
Вообщем-то hellip написал в основном правильно. Только это не совсем задача о ранце.
Хотя это и не так важно. Главное, что полиномиальных алгоритмов не существует и отнестись к ее решению нужно достаточно серьезно.
Во-первых для себя вы должны ее четко сформулировать (у вас не видно фомулировки)
Например так: даны множество N чисел K1, K2,... KN (номиналы купюр числа — от 0.001 до 99999999999999) Amount (то что вы называете данная сумма к разложению) и наверное (хоть у вас это и не прозвучало) R1, R2,...RN множество чисел ограничивающих количество конкретных купюр в наборе — ведь не бесконечное же их количество может быть в реальной задаче
Найти такой целочисленный вектор X1, X2,... XN такой что
X1 < = R1
X2 < = R2...
Xn < = Rn
И
X1*K1 + X2*K2 +... Xn*KN > =Amount
И для любого Y1, Y2,... YN
Если выполнено
Y1 < = R1
Y2 < = R2...
Yn < = Rn
и
Y1*K1 + Y2*K2 +... Yn*KN > =Amount
То значит
X1*K1 + X2*K2 +... Xn*KN < = Y1*K1 + Y2*K2 +... Yn*KN
Таким образом перебрать надо максимум R1*R2*...*RN вариантов (вообще даже меньше)
Теперь о сложности. хотя существуют только экспоненциальные алгоритмы, но есть одно хорошее «но» — рост ведь идет по размерности задачи, по числу купюр, а оно в вашем случае все таки огораниченно. Так, что належда есть на относительно эфективные алгоритмы
Обратите внимание на такие моменты:
При решении таких задач гарантированно эффективные алгоритмы могут быть только при 2 подходах — либо для частных случаев (те надо исходя из того, что вам известно наложить дополнительные условия)
либо при поиске алгоритмов находящих приблизительное решение
Второй важный момент
Если вы хотите производить вычисления на стороне клиента в броузере, то серьезной оптимизации вам достичь не удастся и экспоненциальный рост здесь не причем. Просто довольно большое количество операций при вычислении будет все равно, даже при очень оптимизированных алгоритмах Эта не та задача которую можно реализовать на скриптовых языках.
А вот если ее реализовать на сервере, то тут есть простор для улучшения алгоритма...
Взять хотя бы тот факт что участвуют купюры одних и тех же номиналов всегда. Ведь так? А это много что дает...Но только на стороне сервера
Вообщем присоединяюсь к hellip и Аноним — если захотите посоветоваться — обращайтесь

Вам будет сложно разобраться в решении задач комбинаторной оптимизации, если вы никогда раньше этим не занимались Тем более, что готовых рецептов для вашего конкретного случая все равно нет

+100, мне тоже было бы интересно посмотреть, может, смогу чем-то помочь

2CVA: А есть ли какая-то статистика по тому, на каких данных тестируют? Я думаю, было бы интересно посмотреть на подборку сложных случаев и тогда смотреть, что с ними можно сделать. Так что если у Вас есть такие данные и Вы готовы их куда выложить — было бы неплохо.

2 CVA понятно, еще попробуйте книгу Гэри и Джонсона «Вычислительные машины и труднорешаемые задачи», 1982 года выпуска

2Роман Чепляка, это не вариант, опять при больших суммах будут косяки.
2hellip я хотел, чтобы каждый понял условия. Математик может прочесть постановку мою тз, а вот программист редко знает мат.синтаксис. Нейронную сеть строил, думаю генет.алг. тут не помошник.
Все идеи 0, 1, 2 и ещё кучу использовались — эффект -> 0.

Спасибо за участие, буду изучать NP задачки.

hellip, понятно, что решить все задачи быстро не удастся. Но это же не повод. Симплекс-метод вон тоже теоретически экспоненциальный, однако на практике он работает быстрее полиномиального метода эллипсоидов. Так же и тут: я не предлагаю волшебного способа решить все задачи, я предлагаю методы, которые могут ускорить существенную часть всех практических задач.

Нет, к сожалению, задача Фробениуса эквивалентна упаковке рюкзака, это еще одно свойство всего NP-класса: каждую задачу из этого класса можно свести к любой другой из того же класса.

Cудя по описанию, нужно узнать только разложимо ли данное число или нет, а конкретное (и тем более минимальное) разложение не нужно. В этом случае можно попробовать сделать пару трюков, которые ускорят процесс в большинстве частных случаев. Идеи черпались из английской wiki. Во-первых, нужно найти НОД всех купюр. Если это не 1, то делим все купюры и требуемую сумму на него. Если сумма не делится — округляем вверх (очевидно, требуемую сумму получить всё равно нельзя).
Идея № 0а: если у нас есть купюра 1 — ответ да
Идея № 0 б: если сумма делится на одну из купюр — ответ да
Идея № 1: Если у нас есть только две a1 и a2 купюры и они взаимопросты, то можно получить всё, что больше (a1*a2-a1-a2) = (a1−1) * (a2−1) — 1.
Это, по-моему, уже интересно. Нужно найти две взаимнопростых купюры, минимизирующих (a1−1) * (a2−1). Если мы нашли и требуемая сумма не меньше — она разложима.
Идея № 2: Не такая оптимистичная как №!, но всё же. Если не нашлось двух взаимнопростых купюр или это не дало положительный ответ, то вот ещё один факт:
Если есть N купюр a1,..., aN с общим НОД (a1,..., aN) =1, то разложимо любое число, которое не меньше (a1*...*aN). Эту оценку явно можно улучшить, но это уже к более умным людям.
Таким образом, если идея из № 1 провалилась, стоит поискать маленький комбинации купюр из 3 или 4 с НОД=1.

Естественно идеи № 1 и особенно № 2 нужно применять в случае, когда сумма большая. Иначе решение в лоб может оказаться быстрее.

Что-то стремновато за вашу задачу, это же разновидность задачи об упаковке рюкзака:
ru.wikipedia.org/.../Задача_о_ранце
или игры в тетрис:
ru.wikipedia.org/wiki/Тетрис. Ее можно решить динамическим программированием, но она NP-полная, потому и начинаются траблы в зависимости от размера входных данных. Они принципиально неустранимы, это свойство данного класса задач: перекрывающиеся подзадачи норовят добиться экспоненциального, а то и факториального потребления времени. У Кормена и Лейзерсона найдете оптимизированный алгоритм на C++. Перепишите его на JS или, еще лучше, постройте нейронную сеть. В таких случаях фуззилогика полезнее всего.

Хотя, если честно, я сомневаюсь, что вы сможете ее построить, после вот таких вот высказываний про маткад/матлаб:))

Ваша задача относиться к «задаче комбинаторной оптимизации», которые решаются методами дискретного программирования.
Что бы время решения было минимальным, все-таки без мат модели не обойтись.

В вашем случае скорей всего будет полезен метод ветвей и границ — ru.wikipedia.org/...ветвей_и_границ

Можно бектрекингом. Сначала пытаешься дать сдачу как можно большими купюрами. Если не получается, убираешь одну большую купюру и дополняешь следующей по величине. И т.д.
Например: надо выдать 160 купюрами 50 и 20.

Сначала берем максимум полтинников — это 3. Остается 10, но у нас нет купюр < = 10. Поэтому забираем одну 50 и остальное (160−2*50=60) пытаемся выдать уже меньшими купюрами, т.е. 20-ками.

«если купюр должно быть как можно меньше то целевая функция соответственно»

Всё равно, просто нужно дать ответ — раскладывается или нет (тогда альтернативное решение, следующее за раскладываемой суммой).

Мат.аппарат забыл, тем более это не для mathlab/mathcad надо.
Сам алгоритм реализован, не могу его оптимизировать.
Броузер может тока пару секунд вычислять, а это на javascript сделано — т.е. как тока итераций > 1000 (ну или 5000 — не суть) — всё блин, прерывание выполнение скрипта происходит.

Уменьшить число итераций выход, тока как?...

Підписатись на коментарі