Алгоритм Хиршберга
В предыдущих двух алгоритмах мы имели альтернативу: либо мы умеем восстанавливать ответ, либо можем себе позволить использовать $O(\min (m, n))$ дополнительной памяти. Алгоритм Хиршберга позволяет восстанавливать ответ, используя $O(\min (m, n)+$ $\log (\max (m, n)))$ дополнительной памяти. Идея алгоритма применима не только в этих двух, но и во многих других задачах.
Для определённости будем решать задачу о поиске НОП. В очередной раз применим метод “разделяй и властвуй”: отдельно решим задачу для последовательностей $a_{1}, \ldots, a_{n / 2}$ и $b_{1}, \ldots, b_{m}$, и для последовательностей $a_{n}, \ldots, a_{n / 2+1}$ и $b_{m}, \ldots, b_{1}$. И ту, и другую задачу решим, используя $O(m)$ дополнительной памяти.
Пусть в результате $l[j]$ - длина НОП $a_{1}, \ldots, a_{n / 2}$ и $b_{1}, \ldots, b_{j} ; r[j]$ - длина НОП $a_{n}, \ldots, a_{n / 2+1}$ и $b_{m}, \ldots, b_{m+1-j}$. Тогда длина НОП $a_{1}, \ldots, a_{n}$ и $b_{1}, \ldots, b_{m}$ - это максимум $l[j]+r[m-j]$ по $0 \leqslant j \leqslant m$.
Пусть максимальное значение достигается на $j_{\max }$. Сделаем рекурсивные запуски алгоритма от $a_{1}, \ldots, a_{n / 2}$ и $b_{1}, \ldots, b_{j_{\max }}$ и от $a_{n / 2+1}, \ldots, a_{n}$ и $b_{j_{\max }+1}, \ldots, b_{m}$, чтобы восстановить половинки ответа.
Глубина рекурсии составит $O(\log n)$, каждый рекурсивный запуск может переиспользовать одни и те же $O(m)$ дополнительной памяти, значит, всего понадобится $O(m+\log n)$ дополнительной памяти.
Осталось понять, почему оценка времени работы по-прежнему равна $O(m n)$. Посмотрим на все рекурсивные вызовы на глубине $k$. Во всех них первая последовательность имеет длину $O\left(n / 2^{k}\right)$, а сумма длин вторых последовательностей по всем вызовам на глубине $k$ равна $m$. Значит, суммарное время работы рекурсивных вызовов на глубине $k$ равно $O\left(m n / 2^{k}\right)$. Тогда суммарное время работы всех вызовов есть
$$ \sum_{k} O\left(m n / 2^{k}\right)=O(m n) $$
|
|
Альтернативный способ
Другой способ, работающий по тем же причинам: будем действовать, как обычно при восстановлении ответа, но запоминать будем не предыдущее состояние, а состояние на оптимальном пути от начального с $i=n / 2$.
|
|