Максимальное независимое множество на деревьях (Independent Set)

Независимое множество: $G = (V, E)$ $IS \subseteq V : \ !\exists u, v \in IS: \ (u,v) \in E$ -- не существует вершин, соединенных ребром.

IS[v]      # размер max IS в поддереве с корнем v
IS[l] = 1  # l -- лист
IS[v] = max(sum(IS[w]) + 1, sum(IS[u]))  # берем или не берем текущую вершину
# u -- ребенок, w -- внук

Ассимптотика $O(n)$, т.к. каждая вершина 1 раз поучаствует как корень, 1 раз как сын и 1 раз как внук.

Редукционное расстояние (расстояние Левинштейна, EditDistance)

Вход: две строки s1 и s2 Выход: минимальное количество правок, которые переделывают s1 в s2 Правки:

Бывает еще "взвешенная" версия, в которой у каждой операции есть стоимость.

Задача о выравнивании (Alligment)

Вход: две строки s1 и s2 Задача: записать s2 под s1 так, чтобы максимальное число символов совпало (количество различий было минимально).

Пример: дождь $\rightarrow$ д-ождь дрожь $\rightarrow$ дро-жь

Утверждение: задача о выравнивании для s1 и s2 имеет то же решение, что и edit_distance(s1, s2)

Решение:

e[i, j] = edit_distance(s1[:i+1], s2[:j+1])
e[i, -1] = i  # по хорошему надо в основном алгоритме сдвинуть
e[-1, j] = j  # индексы, чтобы s[0] давало пустую строку
e[i, j] = min(e[i, j-1] + 1  # + c_add
              e[i-1, j] + 1  # + c_remove
              e[i-1, j-1] + (1 if s1[i-1] != s2[j-1] else 0)  # c_replace
          )

Если задача "взвешенная", то единицы заменятся на соответствующие стоимости.

Восстанавливать ответ можно передвигаясь в минимальную ячейку из трех соседей, операция понятна из положения той клетки, куда переходим (диагональ -- замена, горизонталь -- добавление, вертикаль -- удаление).

Замечание: можно решить за $O(|s_1| + |s_2|)$ памяти, если хранить только два столбца. На самом деле за $O(\min{|s_1| + |s_2|})$. Время все равно $O(|s_1|\cdot|s_2|)$. При экономии памяти нет возможности восстановить ответ.

Алгоритм Хиршберга

$O(\min{|s_1| + |s_2|})$ + восстановление ответа.

Лемма: edit_distance(s1, s2) = edit_distance(rev(s1), rev(s2)), где rev(s) = reversed(s) Лемма: пусть s2 = s2_1 + s2_2 -- разбиение s2 на две строки. 1. $\exists i:$ ed(s1, s2) = ed(s1[:i], s2_1) + ed(s1[i:], s2_2). 2. $\forall i:$ ed(s1, s2) <= ed(s1[:i], s2_1) + ed(s1[i:], s2_2) Доказательство: 1. Рассмотрим выравнивание s1 и s2. Если где-нибудь это выравнивание по s2, то в том же месте можно распилить s1, и все будет хорошо. 2. Рассмотрим s1 и s2. Пусть для какого-то j, по которому разбиваем s2 существует какой-то i, для которого ed(s1, s2) > ed(s1[:i], s2[:j]) + ed(s1[i:], s2[j:]). Тогда на основе этих i и j можем получить более короткое выравнивание, чем то оптимально, что мы уже получили. Противоречие.

Следствие: s2 = s2_1 + s2_2 $\Rightarrow \exists i:$ ed(s1, s2) = ed(s1[1:i], s2_1) + ed(s1[n:i+1], rev(s2_2))

Алгоритм: 1. Распилим s2 пополам: s2 = s2_1 + s2_2. 2. Решаем задачу для s1 и s2_1 3. Решаем задачу для rev(s1) и s2_2 (решаем старым способом за $O(|s1|)$ памяти) 4. Смотрим на крайние столбцы для двух решений (соседние столбцы в исходной таблице). Находим min(sum(соотв. ячеек)) (соответствующие ячейки -- диагональные в этих двух столцах) $\Rightarrow$ получаем $i$ из леммы 2 5. Запускаем рекурсивно для (s1[:i] и s2_1) и (s1[i:] и s2_2)

Ответ можно восстановить по парам индексов i и j, запомненных на шаге 4.

Анализ: $T(n) = |s1|\cdot|s2| \frac{|s1|\cdot|s2|}2 + \frac{|s1|\cdot|s2|}4 = O(|s1|\cdot|s2|)$

Такой подход называется Meet in the middle.