Автор работы: Пользователь скрыл имя, 04 Декабря 2013 в 11:05, реферат
Довольно часто на олимпиадах встречаются задачи, провоцирующие к применению алгоритмы перебора. Но простой подсчет числа вариантов убеждает в неэффективности такого подхода. Для решения таких задач используется метод динамического программирования. Суть его заключается в том, что для отыскания решения поставленной задачи решается похожая (или похожие), но более простая. При этом осуществляется переход к еще более простым и так далее, пока не доходят до тривиальной.
Динамическое программирование в теории управления и теории вычислительных систем — способ решения сложных задач путём разбиения их на более простые подзадачи
Введение…………………………………………………………………………………….3
История……………………………………………………………………………………….3
Динамическое программирование…………………………………………..4
Идея динамического программирования………………………………..5
Решение задач динамического программирования………………..7
Заключение……………………………………………………………………………….12
Использованная литература…………………………………………………….13
ФГАОУ «Северо-Восточный
Федеральный Университет им.М.
Институт математики и информатики
Кафедра теории и методики преподавания информатике
Реферат: Динамическое программирование
СВФУ ИМИ ИНФ-11
Петровой Дарии Егоровны
доцент каф. ТМОИ ИМИ СВФУ
Николаева Наталья Васильевна
Якутск
2013
Содержание
Введение
«Знание только тогда знание,
когда оно приобретено усилиями своей
мысли а не памятью.»
Л.Н.Толстой
Довольно часто на олимпиадах встречаются задачи, провоцирующие к применению алгоритмы перебора. Но простой подсчет числа вариантов убеждает в неэффективности такого подхода. Для решения таких задач используется метод динамического программирования. Суть его заключается в том, что для отыскания решения поставленной задачи решается похожая (или похожие), но более простая. При этом осуществляется переход к еще более простым и так далее, пока не доходят до тривиальной.
Динамическое программирование в теории управления и теории вычислительных систем — способ решения сложных задач путём разбиения их на более простые подзадачи. Он применим к задачам с оптимальной подструктурой, выглядящим как набор перекрывающихся подзадач, сложность которых чуть меньше исходной. В этом случае время вычислений, по сравнению с «наивными» методами, можно значительно сократить.
Ключевая идея в динамическом программировании
достаточно проста. Как правило, чтобы
решить поставленную задачу, требуется
решить отдельные части задачи (подзадачи),
после чего объединить решения подзадач
в одно общее решение. Часто многие из
этих подзадач одинаковы. Подход динамического
программирования состоит в том, чтобы
решить каждую подзадачу только один раз,
сократив тем самым количество вычислений.
Это особенно полезно в случаях, когда
число повторяющихся подзадач экспоненциально
велико.
Метод динамического программирования сверху — это простое запоминание результатов решения тех подзадач, которые могут повторно встретиться в дальнейшем. Динамическое программирование снизу включает в себя пере формулирование сложной задачи в виде рекурсивной последовательности более простых подзадач.
История
Словосочетание
«динамическое
Слово «программирование»
в словосочетании «динамическое
программирование» в
Динамическое программирование
Динамическое программирование обычно применяется к задачам, в которых искомый ответ состоит из частей, каждая из которых в свою очередь дает оптимальное решение некоторой подзадачи.
Динамическое программирование полезно, если на разных путях многократно встречаются одни и те же подзадачи; основной технический приём — запоминать решения встречающихся подзадач на случай, если та же подзадача встретится вновь.
В типичном
случае динамическое программирование
применяется к задачам
Из предыдущего рассуждения видно, что решение можно оформить рекурсивно. Но простое применение этого приема очень легко может привести к переполнению стека. Необходимо позаботиться об оптимизации рекурсивных проходов и не вычислять одно и то же значение несколько раз, сделать так называемое отсечение. Можно вообще отказаться от рекурсии и решать задачу "наоборот" — прежде "решить" тривиальные случаи, а затем переходить ко все более сложным. В авторских решениях подобных задач почти всегда встречается второй путь (он несколько быстрее), но в этом занятии рассмотрим оба — первый гораздо доступнее для понимания.
Типовой
алгоритм решения задач методом
динамического
Для решения задач оптимизации существует специальная теория, большая заслуга в ее создании принадлежит Р. Беллману. В общем виде она достаточна сложна, поэтому здесь не рассматривается. В то же время конкретные задачи, рассмотренные ниже, вполне могут сформировать (хотя бы на интуитивном уровне) идеи, лежащие в основе решения задач данного класса.
Первые
две задачи, строго говоря, нельзя отнести
к указанному классу, но приемы, использованные
при их решении, очень сходны с
таковыми у задач, рассматриваемых
на этом занятии. Остальные задачи в
свое время встречались на различных
олимпиадах (а некоторые с тех
пор стали "фольклорными") и
расположены (по мнению автора публикации)
в порядке возрастания
Идея динамического
Оптимальная подструктура в динамическом программировании означает, что оптимальное решение подзадач меньшего размера может быть использовано для решения исходной задачи. К примеру, кратчайший путь в графе из одной вершины (обозначим s) в другую (обозначим t) может быть найден так: сначала считаем кратчайший путь из всех вершин, смежных с s, до t, а затем, учитывая веса ребер, которыми s соединена со смежными вершинами, выбираем лучший путь до t (через какую вершину лучше всего пойти). В общем случае мы можем решить задачу, в которой присутствует оптимальная подструктура, проделывая следующие три шага.
Подзадачи решаются делением их на подзадачи ещё меньшего размера и т. д., пока не приходят к тривиальному случаю задачи, решаемой за константное время (ответ можно сказать сразу). К примеру, если нам нужно найти n!, то тривиальной задачей будет 1! = 1 (или 0! = 1).
Перекрывающиеся подзадачи в динамическом программировании означают подзадачи, которые используются для решения некоторого количества задач (не одной) большего размера (то есть мы несколько раз проделываем одно и то же). Ярким примером является вычисление последовательности Фибоначчи, F3=F2+F1 и F4=F3+F2 — даже в таком тривиальном случае вычисления всего двух чисел Фибоначчи мы уже посчитали F2 дважды. Если продолжать дальше и посчитать F5 , то F2 посчитается ещё два раза, так как для вычисления F5 будут нужны опять F3 и F4. Получается следующее: простой рекурсивный подход будет расходовать время на вычисление решения для задач, которые он уже решал.
Чтобы избежать такого хода событий мы будем сохранять решения подзадач, которые мы уже решали, и когда нам снова потребуется решение подзадачи, мы вместо того, чтобы вычислять его заново, просто достанем его из памяти. Этот подход называется кэширование. Можно проделывать и дальнейшие оптимизации — например, если мы точно уверены, что решение подзадачи нам больше не потребуется, можно выкинуть его из памяти, освободив её для других нужд, или если процессор простаивает и мы знаем, что решение некоторых, ещё не посчитанных подзадач, нам понадобится в дальнейшем, мы можем решить их заранее.
Подводя итоги вышесказанного можно сказать, что динамическое программирование пользуется следующими свойствами задачи:
-перекрывающиеся подзадачи;
-оптимальная подструктура;
-возможность запоминания решения часто встречающихся подзадач.
Динамическое программирование обычно придерживается двух подходов к решению задач:
-нисходящее динамическое программирование: задача разбивается на подзадачи меньшего размера, они решаются и затем комбинируются для решения исходной задачи. Используется запоминание для решений часто встречающихся подзадач.
-восходящее динамическое программирование: все подзадачи, которые впоследствии понадобятся для решения исходной задачи просчитываются заранее и затем используются для построения решения исходной задачи. Этот способ лучше нисходящего программирования в смысле размера необходимого стека и количества вызова функций, но иногда бывает нелегко заранее выяснить, решение каких подзадач нам потребуется в дальнейшем.
Языки программирования могут запоминать результат вызова функции с определенным набором аргументов (мемоизация), чтобы ускорить «вычисление по имени». В некоторых языках такая возможность встроена (например, Scheme, Common Lisp, Perl), а в некоторых требует дополнительных расширений (C++).
Известны сериальное динамическое программирование, включённое во все учебники по исследованию операций, и несериальное динамическое программирование (НСДП), которое в настоящее время слабо известно, хотя было открыто в 1960-х годах.
Обычное динамическое программирование является частным случаем не сериального динамического программирования, когда граф взаимосвязей переменных — просто путь. НСДП, являясь естественным и общим методом для учета структуры задачи оптимизации, рассматривает множество ограничений и/или целевую функцию как рекурсивно вычислимую функцию. Это позволяет находить решение поэтапно, на каждом из этапов используя информацию, полученную на предыдущих этапах, причём эффективность этого алгоритма прямо зависит от структуры графа взаимосвязей переменных. Если этот граф достаточно разрежен, то объём вычислений на каждом этапе может сохраняться в разумных пределах.
Одним из
основных свойств задач, решаемых с
помощью динамического
Решение задач динамического
Распределить 5 однородных партий товара между тремя рынками так, чтобы получить максимальный доход от их продажи. Доход от продажи на каждом рынке G(X)зависит от количества реализованных партий товара Х и представлен в таблице.
Решение:
Объем товара Х(в партиях) |
Доход G(X) | ||
1 |
2 |
3 | |
0 |
0 |
0 |
0 |
1 |
28 |
30 |
32 |
2 |
41 |
42 |
45 |
3 |
50 |
55 |
48 |
4 |
62 |
64 |
60 |
5 |
76 |
76 |
72 |