Динамическое программирование
Сразу оговорюсь - данная статья не претендует на полноту освещения этой темы программирования. Скорее это просто мое понимание. Литературы об этом, кажется, немного (или я плохо искал?..), поэтому я решил написать некую "сборную статью", в которую вложу понемногу из того, что понаходил во многих местах и постараюсь снабдить достаточным кол-вом примеров.
Ну да ладно, приступим собственно к теме статьи... :)
(Возможно что-то будет сразу непонятно - дочитайте до примеров, не поленитесь, возможно станет понятнее)
В типичном случае динамическое программирование применяется к задачам оптимизации, которые не решаются простым перебором (из-за временных ограничений или слишком большого объема необходимой памяти) и жадными алгоритмами (из-за того, что они не дают оптимального результата), а более простой путь решения если и существует, то его нахождение неочевидно. У таких задач может быть много решений и в общем случае это определяет некий показатель (назовем его "качеством" решения), и требуется выбрать оптимальное, при котором данный показатель становится либо минимумом либо максимумом (или еще чем-то... :) - в зависимости от условия задачи).
По своему принципу динамическое программирование напоминает метод "разделяй и властвуй" - задача делится на подзадачи, которые либо являются очевидными, либо сводятся к своим подзадачам и т.д. Но есть и некоторые отличия - например, таких подзадач обычно относительно немного, что позволяет решить каждую только один раз, а результат (то самое "качество") занести в некий массив - такой подход называется memoization (не бейте меня, это не я такое придумал! :))).
Небольшое кол-во подзадач, многие из которых приходится решать много раз называется перекрытием подзадач и является характерным признаком динамического программирования.
Вторым характерным признаком излагаемого метода является оптимальность для подзадач. Говорят, что задача обладает таким свойством, если оптимальное решение задачи содержит оптимальные решения ее подзадач.