Применение метода четырёх русских в задачах ДП на примере задачи о НОП — различия между версиями
Alexandra (обсуждение | вклад) (→Источники) |
Alexandra (обсуждение | вклад) (→Предподсчёт) |
||
Строка 14: | Строка 14: | ||
Посчитаем эти квадраты для строк abbabb и bababb. Возьмём <tex> k = 3 </tex>. Тогда предподсчитанные квадраты, которые понадобятся для дальнейшего вычисления НОП, выглядят так: | Посчитаем эти квадраты для строк abbabb и bababb. Возьмём <tex> k = 3 </tex>. Тогда предподсчитанные квадраты, которые понадобятся для дальнейшего вычисления НОП, выглядят так: | ||
− | + | {| | |
+ | | | ||
+ | {|class="wikitable" style="background-color:#FFF; text-align:center; " | ||
+ | | colspan="2" rowspan="2" | | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | |- | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>0</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |} | ||
+ | | || || || || || || || | ||
+ | | | ||
+ | {|class="wikitable" style="background-color:#FFF; text-align:center; " | ||
+ | | colspan="2" rowspan="2" | | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | |- | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>3</tex> | ||
+ | |<tex>3</tex> | ||
+ | |} | ||
+ | |} | ||
+ | |||
+ | |||
+ | |||
+ | {| | ||
+ | | | ||
+ | {|class="wikitable" style="background-color:#FFF; text-align:center; " | ||
+ | | colspan="2" rowspan="2" | | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | |- | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>3</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>3</tex> | ||
+ | |} | ||
+ | | || || || || || || || | ||
+ | | | ||
+ | {|class="wikitable" style="background-color:#FFF; text-align:center; " | ||
+ | | colspan="2" rowspan="2" | | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | |- | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>a</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>1</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |- | ||
+ | ! style="background-color:#E0FFFF; width: 40px; height: 40px;" |<tex>0</tex> | ||
+ | ! style="background-color:#FFEECC; width: 40px; height: 40px;" |<tex>b</tex> | ||
+ | |<tex>1</tex> | ||
+ | |<tex>2</tex> | ||
+ | |<tex>2</tex> | ||
+ | |} | ||
+ | |} | ||
=== Вычисление НОП на сжатой матрице === | === Вычисление НОП на сжатой матрице === |
Версия 19:45, 7 января 2017
Содержание
Описание алгоритма
Предподсчёт
Рассмотрим задачу о наибольшей общей подпоследовательности для двух последовательностей одинаковой длины. Тогда таблица динамического программирования имеет размер . Разобьём её на квадраты размера следующим образом: выделим каждую -ую строчку, начиная с первой. Аналогично выделяем столбцы.
Требуется, чтобы
делило , но это не является ограничением — можно дописать в конец последовательностей символы, которые не встречались в других местах этих последовательностей (символы для каждой последовательности должны быть разными). Тогда ответ на задачу не изменится, а длину можно «довести» до делителя .Сделаем предподсчёт действия каждого возможного квадрата. Окончательный результат зависит только от значений в верхнем левом «уголке» над квадратом и подстрок, для которых считается ответ — остальные значения в квадрате однозначно считаются с их помощью. Окончательным результатом будут значения в нижнем правом «уголке» квадрата.
Может показаться, что таких уголков может быть много. Но, так как соседние числа в матрице отличаются не более, чем на один, то результат зависит только от константы в верхнем левом элементе матрицы, и возрастания чисел в верхнем и левом крае квадрата. Возрастание чисел будем хранить с помощью битовых масок: сначала
бит кодирует возрастание чисел в верхнем крае квадрата (0 — элемент равен предыдущему, 1 — больше предыдущего на один), потом бит кодируют возрастание чисел в квадрате по левому краю аналогичным образом.Более того, константу в верхнем левом элементе квадрата можно вообще не хранить: её можно прибавить при необходимости к каждому элементу результата.
Посчитаем эти квадраты для строк abbabb и bababb. Возьмём
. Тогда предподсчитанные квадраты, которые понадобятся для дальнейшего вычисления НОП, выглядят так:
|
|
|
|
Вычисление НОП на сжатой матрице
Ответ для самой задачи НОП считается аналогично обычному алгоритму, только рассматривая не каждую ячейку таблицы, а квадраты
. В очередной квадрат (пусть его левый верхний угол находится в ячейке с координатами ) вставляем значения предподсчитанного квадрата, соответствующего данным подстрокам и битовым маскам, и прибавляем ко всем элементам в квадрате число, стоящее в уголке над квадратом, т.е. в ячейке с координатами .Для нашего примера итоговая таблица выглядит так:
Анализ алгоритма
Время работы
При предподсчёте перебирается
(где — мощность алфавита) возможных подстрок первой строки и столько же — второй строки. Для каждой возможной подстроки обеих строк перебирается по битовых масок. Для самого предподсчёта требуется время . Дальнейший алгоритм поиска НОП требует . Тогда суммарное время работы алгоритма составляет . Понятно, что для получения выигрыша в производительности по сравнению с обычным алгоритмом необходимо, чтобы первое слагаемое не превышало второе. Найдём , решив неравенство:
.
.
Пренебрегая
и как , получаемИспользуемая память
Для каждого предподсчитанного квадрата хранятся подстроки длиной
, битовые маски длиной и результат — нижний «уголок» длины . Как уже было подсчитано, всего предподсчитывается квадратов. Дальнейший алгоритм требует , значит, всего требуется памяти.