Слайд 1Динамическое программирование. Примеры задач
Федор Царев
Спецкурс «Олимпиадное программирование»
Лекция 5
13.04.2009
Санкт-Петербург, Гимназия 261
Слайд 2Цель лекции
Изучить еще несколько примеров задач, решаемых с помощью динамического
программирования, и их решения
Слайд 3Признаки возможности применения ДП
Возможность разбиения задачи на подзадачи (метод «разделяй-и-властвуй»)
Наличие
свойства оптимальности для подзадач – оптимальный ответ для большой задачи
строится на основе оптимальных ответов для меньших
Наличие перекрывающихся подзадач
Слайд 4Этапы решения задачи методом динамического программирования
Разбиение задачи на подзадачи
Построение рекуррентной
формулы для вычисления значения функции (включая начальные условия)
Вычисление значения функции
для всех подзадач (важен порядок вычисления)
Восстановление структуры оптимального ответа
Слайд 5Наибольшая возрастающая подпоследовательность
Задана последовательность чисел a1, a2, …, an
Необходимо найти
возрастающую подпоследовательность наибольшей длины
1 5 3 7 1 4 10
15
Слайд 6Перебор?
Число различных подпоследовательностей: (2n – 1)
Можно применять для n ≤
20
Слайд 7Разбиение на подзадачи
Идея: найти наибольшую возрастающую подпоследовательность среди первых i
элементов: a1, a2, …, ai
Попробуйте построить рекуррентную формулу
Более точно: найти
наибольшую возрастающую подпоследовательность среди первых i элементов: a1, a2, …, ai, последний элемент в которой - ai
Слайд 8Рекуррентная формула
d[i] – длина наибольшей возрастающей подпоследовательности, которая заканчивается в
ai
Считается, что максимум равен нулю, если таких индексов j нет
Слайд 9Начальные условия
Можно сделать немного проще
Считаем, что в начало добавлен a0=–∞,
а d[0] = 0
Теперь можно не делать никаких предположений, так
как всегда найдется некоторый индекс j
Слайд 19Программа
d[0] := 0;
for i := 1 to n do begin
max
:= 0;
for j := 1 to i – 1 do
begin
if (a[j] < a[i]) and
(d[j] > max) then begin
max := d[j];
end;
end;
d[i] := max + 1;
end;
Слайд 20Восстановление ответа
Где находится длина L наибольшей возрастающей подпоследовательности?
L := 0;
pos
:= -1;
for i := 1 to n do begin
if (d[i]
> max) then begin
max := d[i];
pos := i;
end;
end;
Слайд 21Вычисление с сохранением информации для восстановления ответа
d[0] := 0;
prev[0] :=
-1;
for i := 1 to n do begin
max := 0;
bestj
:= -1;
for j := 1 to i – 1 do begin
if (a[j] < a[i]) and
(d[j] > max) then begin
max := d[j];
bestj := j;
end;
end;
d[i] := max + 1;
prev[i] := bestj;
end;
Слайд 22Восстановление ответа
procedure restore(i : integer);
begin
if (i > 0) then begin
restore(prev[i]);
write(a[i]);
end;
end;
Слайд 24Время работы
Время работы этого алгоритма – O(n2)
Можно ли быстрее?
Слайд 25Более быстрый алгоритм
Похоже, что от вычисления d[i] никуда не деться
Попробуем
вычислять d[i] быстрее
Пусть last[i] – минимальное последнее число в возрастающей
подпоследовательности длины i
Слайд 26Свойство массива last
Этот массив является неубывающим
Действительно, пусть i < j,
но last[i] > last[j]
Из подпоследовательности длины i можно сделать подпоследовательность
длины j, поэтому last[j] ≤ last[i] (last[j] – минимальный, last[i] – некоторый)
Слайд 27Вычисление d[i]
Находим место в массиве last, на которое следует поставить
a[i] – такую позицию j, что last[j-1] < a[i] ≤
last[j]
Это означает, что максимальная длина подпоследовательности, которая заканчивается в a[i] есть j (d[i] = j)
Позицию j надо искать с помощью двоичного поиска
Время работы алгоритма – O(nlogn)
Слайд 28Упражнения
Продумать, как сохранять информацию для восстановления ответа
Реализовать этот алгоритм
Слайд 29Задача о рюкзаке
Есть рюкзак вместимостью W и n предметов, каждый
из которых характеризуется ценностью pi и весом wi
Необходимо выбрать несколько
предметов так, чтобы их суммарная ценность была максимальна, а суммарный вес не превышал W
Слайд 30Разбиение на подзадачи
Два параметра – число обработанных предметов и вместимость
рюкзака
c[i][j] – максимальная суммарная стоимость, которую можно набрать первыми i
предметами так, чтобы их вес не превосходил j
Слайд 31Рекуррентная формула
Очередной предмет можно либо взять, либо не взять
Слайд 32Начальные условия
c[0][j] = 0 для j=0…W
c[i][0] = 0 для i=0…n
Слайд 33Два способа реализации
Метод заполнения таблицы можно реализовать двумя способами
«Динамика назад»
(этот метод использовался во всех рассмотренных задачах)
«Динамика вперед»
Слайд 34«Динамика вперед»
for i := 0 to n do begin
for j
:= 0 to W do begin
c[i][j] := -INF;
end;
end;
for i :=
0 to n – 1 do begin
for j := 0 to W do begin
if (c[i][j] = -INF) then continue;
c[i+1][j]:=max(c[i][j], c[i+1][j]);
if (j + w[i + 1] <= W) then begin
c[i + 1][j + w[i + 1]] = max(c[i][j] + p[i+1],
c[i + 1][j + w[i + 1]]);
end;
end;
end;
Слайд 35Восстановление ответа
Необходимо запоминать для каждого состояния (i, j) надо ли
брать очередной предмет
Реализуйте сами!
Слайд 36Время работы алгоритма
Время работы этого алгоритма – O(nW)
Таким образом, он
применим только для относительно небольших значений весов предметов
Слайд 37Упражнения
Решите задачу о рюкзаке для случая, когда имеется неограниченное число
предметов каждого типа
Решите задачу о рюкзаке для случая, когда предметы
можно брать не полностью (не золотые слитки, а золотой песок)
Решите смешанную задачу о рюкзаке – часть предметов можно брать только полностью, а остальные – можно и не полностью
Слайд 38Оптимальная триангуляция многоугольника
Задан выпуклый многоугольник
Необходимо разбить его на треугольники, проведя
несколько диагоналей
Суммарный периметр треугольников должен быть как можно меньшим
Кстати, сколько
придется провести диагоналей, если в многоугольнике N углов?
Слайд 39Нумерация вершин многоугольника
Вершины (n+1)-угольника нумеруются числами от 0 до n
При
этом когда говорится о вершине «номер k» имеется в виду
вершина «номер k mod n» (то есть vn=v0, …)
Слайд 40Разбиение на подзадачи
После вырезания одного треугольника, многоугольника распадается на два,
которые можно рассматривать отдельно
Слайд 41Строение оптимального решения
Рассмотрим оптимальную триангуляцию заданного (n+1)-угольника v0,v1, …, vn
Ребро
v0vn входит в некоторый треугольник
Пусть это треугольник v0vnvk
Тогда стоимость триангуляции
равна
Стоимость этого треугольника +
Стоимость триангуляции v0, v1, …, vk +
Стоимость триангуляции vk, vk+1, …, vn
Слайд 42Рекуррентная формула
d[i][j] – минимальная стоимость триангуляции многоугольника vi-1…vj (1≤i
в d[1][n]
Начальные условия:
d[i][i] = 0
d[i][j] = -∞ при i >
j
Слайд 43Восстановление ответа
Для каждой подзадачи необходимо запомнить оптимальное значение числа k
Реализуйте
самостоятельно!
Слайд 44Упражнения
Пусть стоимостью треугольника считается его площадь. Как найти оптимальную триангуляцию?
Пусть
необходимо минимизировать суммарную длину проведенных диагоналей. Как найти оптимальную триангуляцию
в этом случае?
Слайд 45Выводы
Рассмотрены три примера задач, решаемых методом динамического программирования
Метод заполнения таблицы
может быть реализован двумя способами – «динамика вперед» и «динамика
назад»
Необходимо следить за тем, чтобы не выполнялись переходы из недостижимых состояний
Слайд 46Спасибо за внимание!
Вопросы? Комментарии?
fedor.tsarev@gmail.com