В общем случае, когда значения монет могут быть произвольными, представляемая вами проблема называется Проблема с ранцем и, как известно, относится к NP-полной ( Pearson, D. 2004 ), поэтому поэтому не разрешима в полиномиальное время, такое как динамическое программирование.
Возьмите патологический пример: x [2] = 51, x [1] = 50, x [0] = 1, X = 100. Затем требуется, чтобы алгоритм «рассмотрел» возможности внесения изменений с помощью монеты. x [2], альтернативно внося изменения, начиная с x [1]. Первый шаг, используемый с национальной чеканкой, иначе известный как алгоритм жадности - до , «используйте самую большую монету меньше рабочего итога», не будет работать с патологическими чеканками , Вместо этого такие алгоритмы испытывают комбинаторный взрыв, который превращает их в NP-завершенные.
Для некоторых специальных схем размещения монет, таких как практически все в фактическом использовании, включая фиктивную систему X [i + 1] == 2 * X [i], существуют очень быстрые алгоритмы, даже O (1) в выдуманном случае, чтобы определить лучший результат. Эти алгоритмы используют свойства значений монет.
Мне не известно о динамическом программном решении, которое использует преимущества оптимальных подрешения, как того требует мотив программирования. В общем случае проблема может быть решена с помощью динамического программирования только в том случае, если она может быть разложена на подзадачи, которые при оптимальном решении могут быть преобразованы в решение, которое доказуемо оптимально. То есть, если программист не может математически продемонстрировать («доказать»), что перекомпоновка оптимальных промежуточных решений задачи приводит к оптимальному решению, то динамическое программирование не может быть применено.
Примером, обычно приводимым для динамического программирования, является приложение для умножения нескольких матриц. В зависимости от размера матриц выбор можно оценить A · B · C в качестве одной из двух эквивалентных форм: ((* A · B ) · C ) или ( A · ( B · C )) приводит к расчеты разного количества умножений и сложений. То есть один метод является более оптимальным (более быстрым), чем другой метод. Динамическое программирование - это мотив, который сводит в таблицу вычислительные затраты различных методов и выполняет фактические вычисления в соответствии с графиком (или программа ), вычисленным динамически во время выполнения.
Ключевой особенностью является то, что вычисления выполняются в соответствии с вычисленным расписанием, а не путем перечисления всех возможных комбинаций - независимо от того, выполняется ли перечисление рекурсивно или итеративно. В примере умножения матриц на каждом шаге выбирается только умножение с наименьшей стоимостью. В результате, возможные затраты на неоптимальные графики промежуточных затрат никогда не рассчитываются. Другими словами, расписание рассчитывается не путем поиска всех возможных расписаний для оптимального, а скорее путем постепенного построения оптимального расписания из ничего.
Номенклатуру «динамическое программирование» можно сравнить с «линейным программированием», в котором «программа» также используется в значении «планировать».
Чтобы узнать больше о динамическом программировании, обратитесь к величайшей книге об алгоритмах, известных мне до сих пор, «Введение в алгоритмы» Кормена, Лизерсона, Ривеста и Стейна. «Ривест» - это «R» «RSA» и динамическое программирование - это всего лишь одна из десятков глав.
Обложка рекомендуемой книги. http://ecx.images -amazon.com / изображения / I / 41hJ7gLDOmL._SL500_AA300_.jpg