Загрузил rodzher.zet

Практика по алгоритмам Жадность, центроидная декомпозиция

Реклама
Первый курс, весенний семестр 2019/20
Практика по алгоритмам #9
Жадность, центроидная декомпозиция
13 марта
Собрано 16 апреля 2020 г. в 15:12
Содержание
1. Жадность, центроидная декомпозиция
1
2. Разбор задач практики
3
3. Домашнее задание
3.1. Обязательная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Дополнительная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
7
7
4. Разбор домашнего задания
4.1. Обязательная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Дополнительная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
8
10
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
Жадность, центроидная декомпозиция
1. PTAS для partition
Переберём, куда кладём 2𝑘 максимальных по весу предметов. Остаток разложим жадно.
1
Докажите оценку (1 + 𝑘1 )-OPT. (*) Докажите оценку (1 + 2𝑘
)-OPT.
2. Приближение Set Cover
a) Реализуйте жадное (ln 𝑛)-приближение максимально быстро.
b) Модифицируйте жадное решение для взвешенного случая:
каждое множество имеет вес, мы ищем покрытие min веса.
3. Итеративное приближение коммивояжера
Пусть на каких-то вершинах (точки на плоскости) уже построен цикл.
Найдем ближайшую к циклу вершину, вставим ее в то место, к которому она ближайшая.
Оцените ошибку и время работы алгоритма.
a) Ближайшая к циклу = ближайшая к вершинам цикла.
b) (*) Ближайшая к циклу = ближайшая к рёбрам цикла.
4. Минимум на пути дерева
Дано дерево, каждая вершина имеет вес.
Отвечать на запросы «минимальный вес на пути из 𝑢 в 𝑣».
a) За 𝒪(log 𝑛)
(вспомните код! если не уверены, напишите псевдокод на бумажке)
b) За 𝒪(log log 𝑛) (придумайте, как ускорить; “LCA за 𝒪(быстро)” запрещён!)
5. Максимальный короткий путь в дереве
Дано дерево, каждая вершина имеет неотрицательный вес.
Среди путей длины ровно 𝐿 найти путь max веса. 𝒪(𝑛 log 𝑛).
(*) Среди путей длины 6 𝐿 найти путь max веса. 𝒪(𝑛 log 𝑛).
6. Покраска близких соседей в дереве
Дано дерево, каждая вершина имеет цвет, изначально равный нулю. Запросы: «покрасить
все вершины на расстоянии 6 𝑑 от вершины 𝑣 в цвет 𝑐», «вывести цвет вершины 𝑣».
a) Все запросы на чтение идут после всех запросов обновления. Offline. 𝒪((𝑚 + 𝑛) log 𝑛).
b) Запросы в произвольном порядке. 𝒪(log 𝑛) на изменение, 𝒪(log2 𝑛) на чтение.
7. Gcd на отрезке
Дан массив натуральных чисел. Отвечать на запросы «gcd на отрезке [𝐿, 𝑅]» за 𝒪(log(𝐶𝑛)).
Массив не меняется.
8. Приближённые расстояния в ацикличном графе
Дан ацикличный граф, для каждой вершины приближённо найти число достижимых.
Точно умеем решать за 𝒪(𝑛𝑚/𝑤), тут хотим за 𝒪(𝑛 + 𝑚).
9. Пятачок, у тебя есть дома ружье?
Даны 𝑛 непересекающихся кругов на плоскости. Мы стоим в точке (0, 0) и можем стелять
по прямой. Минимальным числом выстрелов проткнуть все круги.
1/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
10. (*) Сумма сумм высот детей
Решим задачу « число путей в дереве длины ровно 𝐿» динамикой по дереву.
𝑓 [𝑣, 𝑖] – число вершин в поддереве 𝑣 на расстоянии 𝑖 от 𝑣.
При пересчёте динамики обычно используют естественную оптимизацию – приливать меньших (по высоте) детей к большему.
Докажите, что полученное решение работает за 𝒪(𝑛).
11. (*) Задача о надстроке
Даны строки 𝑠1 , . . . , 𝑠𝑛 , найти строку 𝑆 min длины: все 𝑠𝑖 – подстроки 𝑆.
a) (2 ln 𝑛)-приближение.
b) Простой жадный приближенный алгоритм.
2/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
Разбор задач практики
1. PTAS для partition
OPT – min вес max части.
При жадной стратегии части∑︀будут отличаться на 6 веса одного (наибольшего) предмета 𝑤.
Тогда вес большей части 6 𝑤2𝑖 +𝑤 6 OPT + 𝑤2 .
Пусть распределили 2𝑘 предметов оптимально. Если в большую часть больше ничего не
добавится, то это оптимум.
Иначе разница ∑︀между частями,
аналогично жадной стратегии, будет не более 𝑤2𝑘+1 .
∑︀
2𝑘+1
𝑤𝑖
𝑤𝑖
𝑤/2
2OPT
1
Тогда 𝑤2𝑘+1 6 2𝑘+1 6 2𝑘+1 6 2𝑘+1 6 OPT
⇒ погрешность 6 OPT
6 2𝑘
OPT.
𝑘
2. Приближение Set Cover
Будем считать, что |𝐴| – число ещё не покрытых элементов, а не исходный размер.
a) ∀𝑖 = 0..𝑛 заведем sets[𝑖] – вектор множеств, в которых 𝑖 еще не покрытых элементов.
Помним актальный размер множеств (число еще не покрытых эелементов).
Идем по массиву sets с конца. Видим множество 𝑆 ∈ sets[𝑖]. Если |𝑆| = 𝑖, берем 𝑆 в
ответ.
Взяв в ответ 𝑆, перебираем 𝑥 ∈ 𝑆, перебираем 𝑇 : 𝑥 ∈ 𝑇 . Чтобы делать это быстро, храним
двудольный граф из элементов и множеств.
Выкидываем 𝑥 из 𝑇 , уменьшаем |𝑇 |, добавляем 𝑇 в sets[|𝑇
|].
∑︀
Каждое множество 𝑆 встретим |𝑆| раз. Итого 𝒪(𝑛 + |𝑆𝑖 |)
|𝑆|
.
b) Алгоритм: выбираем каждый раз множество с max cost(𝑆)
6 OPT
(!).
Пусть оставалось покрыть 𝑘 элементов и выбрали 𝑆. Тогда верно cost(𝑆)
|𝑆|
𝑘
OPT
Тогда за каждый покрытый впервые элемент мы сейчас «заплатим» 6 𝑘 .
Более грубая оценка: за 𝑖 = 0..|𝑆| − 1 покрытый сейчас элемент заплатим 6 OPT
.
𝑘−𝑖
∑︀𝑘=1 OPT
Итого заплатим 6 𝑘=𝑛 𝑘 6 ln 𝑛 · OPT.
Доказательство (!): рассмотрим множества 𝐴1 , 𝐴2 , . . . , 𝐴𝑘 в оптимальном ответе.
Пусть каждый элемент покрывается первым 𝐴𝑖 и только им;
А цена множества разбивается по элементам, которые оно покрывает.
Тогда сумма этих удельных стоимостей и есть OPT.
. Это множество нам подойдёт.
Значит одна из них 6 OPT
𝑛
3. Итеративное приближение коммивояжера
a) Если брать вершину, ближайшую к вершинам цикла, получим то же самое, что приближение через MST.
То есть 2-приближение. Вершины добавляются в том порядке, что в алгоритме Прима.
Обход тоже получается точно такой же, как при одном из обходов дерева.
Это можно показать индукцией по 𝑛.
Рассмотрим лист, добавленный последним. До него по индукции результат алгоритмов
был одинаков.
В обоих алгоритмах придем в лист из предка, свернем туда же, куда сворачивали из
предка.
b) Если брать вершину, ближайшую к ребрам цикла, выйдет не хуже прошлго пункта.
Якобы. Но почему?
3/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
4. Минимум на пути дерева
a) Строим centroid decomposition. Для каждого центроида 𝑥 идем dfs-ом в 𝐶(𝑥), поддерживая минимум на пути от 𝑥 до текущей вершины 𝑣. Cохраняем этот минимум в
pathmin[𝑣, 𝑑𝑥 ]. 𝒪(𝑛 log 𝑛) на предподсчет.
На запрос ⟨𝑢, 𝑣⟩ ищем центроид 𝑥 : 𝑢, 𝑣 ∈ 𝐶(𝑥) ∧ 𝑥 ∈ path(𝑢, 𝑣). Это общий предок в дереве
декомпозиции. Ищем за высоту дерева декомпозиции, 𝒪(log 𝑛).
Отвечаем min(pathmin[𝑢, 𝑑𝑥 ], pathmin[𝑣, 𝑑𝑥 ]).
b) Найдем быстрее нужный центроид.
Предпосчитаем также up[𝑣, 𝑑] = 𝑥 : 𝑣 ∈ 𝐶(𝑥) ∧ 𝑑𝑥 = 𝑑 (то есть предка 𝑣 на уровне 𝑑). По
сути, для каждой вершины создали массив предков в дереве декомпозиции.
Для вершин 𝑢, 𝑣 искомый центроид – последний совпадающий элемент в массивах up[𝑢]
и up[𝑣], ищем его бинпоиском.
5. Максимальный короткий путь в дереве
Переберем центроид 𝑥, который будет на пути.
За dfs по 𝐶(𝑥) считаем массив 𝑤𝑥 [𝑑] – max вес пути до вершины на глубине 𝑑, 𝑑 6 |𝐶(𝑥)|.
Снова dfs по 𝐶(𝑥). Вот dfs стоит в вершине 𝑣 на глубине 𝑑 с весом пути 𝑠. Обновляем ответ
величиной 𝑠 + 𝑤𝑥 [𝐿 − 𝑑].
Но это может дать путь с самопересечением.
Чтобы этого избежать, храним 𝑤𝑥 не для всей 𝐶(𝑥), а для нескольких рассмотренных поддеревьев.
Обходя очередное поддерево 𝑥, только обновляем ответ.
Затем обходим поддерево второй раз, обновляя 𝑤𝑥 .
Теперь хотим пути длины 6 𝐿. Нужно поддерживать префиксные максимумы 𝑤𝑥 .
Способ 1. Сортируем поддеревья 𝑥 по возрастанию их размеров 𝐶1 , 𝐶2 , . . . Обходим их в
таком порядке.
Тоже два обхода каждой 𝐶𝑖 . На первом релаксруем ответ, на втором обновляем 𝑤𝑥 .
После второго обхода надо обновить префиксные максимумы. Длина массива 𝑤𝑥 сейчас станет 6 |𝐶𝑖 |, т.е. сделали 𝒪(|𝐶𝑖 |) операций.
Итого 𝒪(|𝐶(𝑥)|), в сумме 𝒪(𝑛 log 𝑛).
Способ 2. Храним по два максимума в 𝑤𝑥 [𝑑].
Второй max среди путей, ведущих не в то поддерево, где первый max.
Обходим всю 𝐶(𝑥) и считаем 𝑤𝑥 .
Второй раз обходим всю 𝐶(𝑥) и обновляем ответ.
Если max путь пересекается в путем в текущую 𝑣, надо брать второй максимум.
Чтобы определить, есть ли пересечение, запомним в 𝑤𝑥 [𝑑] не только вес пути, но и соседа 𝑥,
с которого начался этот путь. То же самое помним и во втором dfs.
6. Покраска близких соседей в дереве
a) Любой путь 𝑣
𝑢 длины 𝑑 проходит через некоторую 𝑥 : 𝑣, 𝑢 ∈ 𝐶(𝑥).
Лениво сохраним обновления в центроидах, в конце применим их все.
При 𝑖-м запросе ⟨𝑣, 𝑑, 𝑐⟩ поднимаемся по 𝑥 – предкам 𝑣 и добавляем в список обновлений
𝑥 запись ⟨𝑑 − dist[𝑣, 𝑑𝑥 ], 𝑐, 𝑖⟩.
В конце для каждого центроида сортируем по времени все скопленные в нем обновления.
Полезно удалить лишние – те, которые перекрываются другими и по расстоянию, и по
времени.
4/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
Если есть обновления ⟨𝑑1 , 𝑐1 , 𝑡1 ⟩, ⟨𝑑2 , 𝑐2 , 𝑡2 ⟩ : 𝑑1 6 𝑑2 , 𝑡1 6 𝑡2 , то первое можно выкинуть.
Сложим обновления в стек, возрастающий по времени. При обработке ⟨𝑑, 𝑐, 𝑡⟩ снимаем со
стека все запросы с расстоянием 6 𝑑.
Тогда стек будет возрастать по времени и убывать по расстоянию.
Теперь можно из каждого центроида 𝑥 протолкнуть все изменения.
Обойдем 𝐶(𝑥) bfs-ом, поддерживая указатель в стеке обновлений 𝑥 на текущее расстояние.
Крася вершину, запомним время покраски. Если из другого центроида придет покраска
с меньшим временем, не применим ее.
b) Будем поддерживать стек, как в прошлом пунтке, но сразу в процессе. Время 𝒪(log 𝑛).
Время, потраченное на уменьшение стека, самортизируется.
Чтобы узнать цвет вершины 𝑣, пройдемся по ее предкам-центроидам 𝑥. В стеке 𝑥 бинпоиском найдем самую позднюю запись с расстоянием 6 dist[𝑣, 𝑑𝑥 ].
Среди выбранных по предкам записей выберем самую позднюю по времени.
7. Gcd на отрезке
Массив – это дерево. Можно на нем строить centroid decomposition. Дальше считать gcd[𝑣, 𝑑]
и отвечать на запросы, как обычно: по 𝑣, 𝑢 находить 𝑥 : 𝑢, 𝑣 ∈ 𝐶(𝑥) ∧ 𝑥 ∈ path(𝑢, 𝑣), отвечать
gcd(gcd[𝑢, 𝑑𝑥 ], gcd[𝑣, 𝑑𝑥 ]). Можно даже за 𝒪(log log 𝑛 + log 𝐶).
8. Прибилижённые расстояния в ацикличном графе
Каждой вершине сгенерили 𝑥𝑣 = random[0..1].
Ответ для вершины 𝑣 равен 1/𝑥, где 𝑥 – min достижимый из 𝑣, не считая 𝑥𝑣 .
∫︀
∫︀
𝑘+1
|01 =
𝐸[min(𝑥1 , . . . , 𝑥𝑘 )] = 𝑘 𝑥(1 − 𝑥)𝑘−1 𝑑𝑥 = −𝑥(1 − 𝑥)𝑘 |10 + (1 − 𝑥)𝑘 𝑑𝑥 = (1−𝑥)
𝑘+1
1
.
𝑘+1
9. Пятачок, у тебя есть дома ружье?
Решим задачу для отрезков на прямой.
Первый выстрел надо сделать в min правый конец. Выкинуть простреленные, решить задачу
для оставшихся отрезков.
Вернемся к кругу. Заметим, что после первого выстрела круг разомкнется в прямую.
Более того, для каждого выстрела (в конец отрезка) однозначно определяется следующий.
Найдем двумя указателями для каждого выстрела 𝑟𝑖 следующий 𝑟𝑗 : 𝑟𝑖 < 𝑙𝑗 .
Если первый выстрел в 𝑟𝑖 , то надо переходить к следующему до момента 𝑟𝑛+𝑖 6 𝑟𝑗 (удвоили
круг).
Уже можем за 𝒪(𝑛2 ) для каждого варианта первого выстрела посчитать ответ.
За 𝒪(𝑛 log 𝑛). Насчитаем to[𝑥][𝑖] – прыжок из точки 𝑥 на 2𝑖 шагов вперед.
Перебираем первый выстрел и бинпоиском считаем, сколько хватит выстрелов.
10. (*) Сумма сумм высот детей
Суммарное время всех приливаний в вершине – сумма высот всех детей, кроме максимального.
Заметим, что для оценки времени построения кучи оценивали похожую величину: сумму
высот всех вершин.
Из соображений монотонности разумных функций асимптотики, чтобы на практике догадаться, что в общем случае сумма без максимума – 𝒪(𝑛), можно посмотреть сумму на «бамбуке», на полном бинарном дереве, на «солнышке».
5/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
На бамбуке сумма 0, на солнышке сумма 𝑛 − 2, на полном бинарном дереве 𝒪(𝑛).
Решение. Рассмотрим рёбра, направленные из вершин в самое глубокое поддерево.
Такие ребра все дерево покрывают путями, пути не пересекаются.
Высота 𝑣 равна длине пути, идущего из нее вниз.
Искомая величина равна сумме длин всех путей. Длина каждого прибавляется в предке
начала пути. Середины путей не прибавляются, ибо направлены в самое глубокое поддерево.
В рёбрах эта величина 6 𝑛 − 1.
В вершинах 6 2𝑛 − 1: 6 𝑛 − 1 не-концов и 6 𝑛 концов, все концы в листьях.
P.S. Такое же утверждение не про глубины, а про размеры не верно. На полном бинарном
дереве будет Θ(𝑛 log 𝑛).
11. (*) Задача о надстроке
a) 2 ln 𝑛-приближение. Стр. 20 в книге Вазирани.
Посмотрим на все возможные сцепления пар строк: 𝜎𝑖,𝑗,𝑘 = 𝑠𝑖 + 𝑠𝑗 [𝑘 :] при 𝑠𝑖 [: −𝑘] = 𝑠𝑗 [𝑘 :].
∀𝑝 ∈ {𝜎𝑖,𝑗,𝑘 } строим множество 𝑆𝑝 из 𝑠𝑖 , являющихся подстроками 𝑝.
Хотим все 𝑠𝑖 покрыть множествами min веса, где 𝑆𝑝 весит |𝑝|.
Если какие-то 𝑆𝑝1 , . . . , 𝑆𝑝𝑚 попали в покрытие, отвечаем 𝑝1 . . . 𝑝𝑚 .
Покрытие можем ln 𝑛 приблизить. Надо показать, что покрытие 2-приближает.
Рассмотрим ответ 𝑠1 . . . 𝑠𝑛 . Пусть 𝑠𝑖1 – последняя, пересекающая 𝑠1 . 𝑠𝑖2 – последняя, пересекающая 𝑠𝑖1 +1 . И так далее.
Тогда есть покрытие из строк 𝜎1,𝑖1 ,𝑘1 , 𝜎𝑖1 +1,𝑖2 ,𝑘2 , . . .
В оптимальное покрытие участки строк от конца 𝑠𝑖𝑗 +1 до начала 𝑠𝑖𝑗+1 +1 входят один раз,
у нас ровно два раза.
⇒ нашли не хуже, чем 2-приближение.
b) Пока строк больше одной, взять две с max наложением и объединить.
Умеют доказывать, что это 3.5-приближение (статья в формате ps).
Есть гипотеза, что это 2-приближение. Это умеют доказывать для строк длины 6 4 (статья студентов АУ).
6/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
Домашнее задание
3.1. Обязательная часть
1. (2) Хорновские формулы
SAT-формула называется Хорновской, если в каждом дизъюнкте не более одного отрицания.
Найти решение. Оценить время работы.
2. (2) Размен
Есть монеты стоимостей 𝑐1 , . . . , 𝑐𝑛 . Найти min 𝑋: этими монетами нельзя разменять 𝑋.
3. (2) Путь с заданным XOR
Дано дерево и число 𝑆. Найти путь, XOR на котором равен 𝑆. 𝒪(𝑛 log 𝑛) времени, 𝒪(𝑛) памяти.
(a) (1) веса на рёбрах; (b) (1) веса в вершинах, путь простой.
4. (3) Число путей длины от 𝐿 до 𝑅
Дано невзвешенное дерево. Посчитать число простых путей в дереве длины от 𝐿 до 𝑅.
a) (2) 𝒪(𝑛 · poly(log 𝑛))
b) (1) 𝒪(𝑛 log 𝑛)
5. (2) Ближайшая чёрная вершина
Дано невзвешенное дерево. Изначально все вершины белого цвета.
Научиться отвечать на запросы: покрасить белую вершину в чёрный; к заданной вершине
найти ближайшую чёрную вершину. 𝒪(𝑛 log 𝑛) на предподсчёт и 𝒪(log 𝑛) на запрос в online.
(+1) добавим запрос “покрасить чёрную в белый”, 𝒪(log2 𝑛) на запрос.
3.2. Дополнительная часть
1. (3) Быстрый centroid decomposition
Дано дерево. Построить decomposition глубины не более log 𝑛 за 𝑜(𝑛 log 𝑛).
2. (3) Mex на пути
Дано дерево, в каждой вершине число. Отвечать на запросы «mex на пути из 𝑢 в 𝑣».
Mex (minimal excluded) – минимальное целое неотрицательное число, отсутствующее в мультимножестве.
3. (3) Дерево Штейнера
Дерево Штейнера для множества вершин 𝑇 в графе 𝐺 – такой связный подграф 𝐺, содержащий все вершины из 𝑇 , что суммарный вес всех ребер подграфа минимален. Задача – найти
дерево Штейнера. Веса неотрицательны. Граф неориентированный.
a)
b)
c)
d)
e)
(0.5) Для |𝑇 | = |𝑉 | найти за 𝒪(𝐸 log 𝑉 )
(0.5) Для |𝑇 | = 2 найти за 𝒪(𝐸 log 𝑉 )
(0.5) Для |𝑇 | = 3 найти за 𝒪(𝐸 log 𝑉 )
(0.5) Для |𝑇 | = 4 найти за 𝒪(𝑉 3 )
(1) Для |𝑇 | = 𝑘 найти за 𝒪(𝑉 3 + 3𝑘 𝑉 )
7/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
Разбор домашнего задания
4.1. Обязательная часть
1. Хорновские формулы
Если в каждом клозе больше одного литерала, подходят все единицы.
Пока есть клозы из одного литерала, надо подставлять этот литерал.
Реализация за 𝒪(𝑛+𝑚). Строим двудольный граф на переменных и клозах. При подстановке
переменной надо перебрать ее соседей-клозов и уменьшить их степень.
Можно класть клозы степени один в очередь, можно запускаться от них рекурсивно.
2. Размен
Сортируем монеты по возрастанию.
Смотрим на 𝑐𝑖 . Если сейчас 𝑋 < 𝑐𝑖 , то конец, мы никогда не наберем 𝑋.
Если 𝑋 > 𝑐𝑖 , то мы точно можем набрать все веса [1, 𝑋 + 𝑐𝑖 ], но пока не можем 𝑋 + 𝑐𝑖 + 1.
3. Путь с заданным XOR
a) Если веса на ребрах, достаточно найти две вершины, у которых равный XOR на пути до
корня.
За один dfs считаем 𝑥[𝑣] – XOR от корня до всех вершин. Кладем в HashMap 𝑥[𝑣] → 𝑣.
Когда нашли 𝑥[𝑣]: в HashMap есть ⟨𝑥[𝑣] ˆ 𝑆, 𝑢⟩, поднимаемся от обеих к корню, выкидываем
пересечение.
b) Centroid decomposition.
Обрабатываем центроил 𝑎. Будем считать 𝑥[𝑣] – XOR на пути 𝑎
𝑣 (с учетом веса 𝑥) и
класть их в HashMap.
Исходно в HashMap есть только 0, пустой путь.
Каждое поддерево 𝑎 дважды обходим dfs-ом.
Первый обход. Находясь в 𝑣, ищем 𝑥[𝑣] ˆ 𝑤𝑎 ˆ 𝑆 в HashMap. Если он там есть, нашли путь.
Во втором обходе складываем все 𝑥[𝑣] в HashMap.
Время такое же, как у построения декомпозиции, 𝒪(𝑛 log 𝑛).
Не храним старые HashMap’ы, только один в каждый момент. Так что память 𝒪(𝑛).
4. Число путей длины от 𝐿 до 𝑅
Centroid decomposition.
Для каждого центроида 𝑥 делаем dfs по 𝐶(𝑥) и считаем для каждой глубины, сколько на
ней вершин. Записываем в массив count[0..|𝐶(𝑥)|].
|𝐶(𝑥)|
𝑅−𝑖
∑︀
∑︀
Теперь считаем 𝑆(𝑥) =
count[𝑖] ·
count[𝑗].
𝑖=0
𝑗=𝐿−𝑖
Чтобы делать это за 𝒪(|𝐶(𝑥)|), посчитаем префиксные суммы.
Но посчитали лишние пути, идущие в одно и то же поддерево, то есть не простые.
В конце (после устранения лишних) ответ поделить на два, так как учли все пути в две
стороны.
Один из способов борьбы с лишним – посчитать, сколько таких лишних путей и вычесть.
Для каждого 𝑣 – ребенка 𝑥 (в исходном дереве) считаем 𝑆(𝑣) (с поправкой на то, что рас-
8/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
стояния по-прежнему считаются от 𝑥).
Каждый 𝑥 обработали за 𝒪(|𝐶(𝑥)|), итого 𝒪(𝑛 log 𝑛). Не обязательно строить декомпозицию
явно, можно считать всё «на лету», тогда память 𝒪(𝑛).
5. Ближайшая чёрная вершина
Centroid decomposition.
Для каждого центроида 𝑥 храним ближайшую чёрную вершину в 𝐶(𝑥) и расстояние 𝑏[𝑥] до
нее.
При покраске вершины в чёрный проходим по ее предкам в декомпозиции и обновляем для
них ближайшую чёрную.
При запросе ближайшей чёрной вершины к 𝑣 проходим по ее предкам 𝑥, обновляем минимум
величиной 𝑏[𝑥] + dist[𝑣, 𝑑𝑥 ].
Если надо уметь перекрашивать в белый, храним для 𝑥 set пар «расстояние, номер» всех
чёрных вершин в 𝐶(𝑥).
Асимптотика умножается на log 𝑛 за счет обращения к set на каждом уровне.
Запрос ближайшей чёрной остается 𝒪(log 𝑛), так как нахождение минимума в set за 𝒪(1).
9/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
4.2. Дополнительная часть
1. Быстрый centroid decomposition
Построим схожую структуру: если 𝑥 – центроид 𝑘-го уровня, то при удалении 𝑥 𝐶(𝑥) распадется на компоненты размера < 2𝑘 .
Наша цель – за 𝒪(𝑛) построить дерево centroid decomposition (обозначим TCD). Внизу листья (центроиды уровня 0), сверху корень (центроид уровня 6 1 + ⌊log(𝑛 − 1)⌋).
Решение: одна рекурсивная процедура 𝑔𝑜(𝑣), которая строит TCD для поддерева 𝑣 и возвращает (1) размер поддерева; (2) вектор центроидов, убывающий по уровню центроида
(стек). В основании вектора корень полученной TCD. Если этот корень не 𝑣, после его выкидывания осталась компонента с 𝑣, сделаем с ней то же самое и так далее. Теперь наша
задача научиться считать результат 𝑔𝑜(𝑣) по результатам детей. Пусть мы получили пары ⟨𝑠𝑖𝑧𝑒1 , 𝑠𝑡𝑎𝑐𝑘1 ⟩, ⟨𝑠𝑖𝑧𝑒2 , 𝑠𝑡𝑎𝑐𝑘2 ⟩, . . . В стеке лежат центроиды 𝑢, упорядоченные по рангу
𝑟𝑎𝑛𝑘[𝑢]. Сверху максимальный. Нужно научиться быстро (за амортизированную 𝒪(1)) выбирать то 𝑖𝑚𝑎𝑥 : 𝑐 = 𝑠𝑡𝑎𝑐𝑘𝑖𝑚𝑎𝑥 .𝑡𝑜𝑝(), 𝑟 = 𝑟𝑎𝑛𝑘[𝑐], 𝑟 максимален. Теперь два случая.
a) Если сумма всех 𝑠𝑖𝑧𝑒𝑖 хотя бы 2𝑟 , то говорим, что 𝑣 – центроид ранга 𝑟 + 1, все 𝑠𝑡𝑎𝑐𝑘𝑖 .𝑡𝑜𝑝()
теперь ссылаются на него. Вернём стек 𝑟𝑒𝑠 из одной вершины 𝑣.
b) Иначе корень TCD – 𝑐. Мы снимаем со стека 𝑖𝑚𝑎𝑥 верхний элемент 𝑐; решаем задачу для
остатка, получаем стек 𝑟𝑒𝑠; верхней в 𝑟𝑒𝑠 вершине добавляем ссылку на 𝑐; кладём 𝑐 на
вершину стека 𝑟𝑒𝑠; возвращаем 𝑟𝑒𝑠.
Доказательство оценки времени работы будет позже. Структуру предлагается придумать
самостоятельно.
2. Mex на пути
Решение в offline.
Сначала решим для запросов на отрезках массива.
√
Алгоритм Мо (см. предыдущий семестр) за 𝒪(𝑛 𝑞) для массива длины 𝑛 и 𝑞 запросов.
Группируем запросы по левой границе в [0..𝑘), [𝑘..2𝑘), . . . В каждой группе обрабатываем
запросы в порядке возрастания правой границы.
𝒪(𝑘𝑞 + 𝑛 𝑛𝑘 ). Берем 𝑘 = √𝑛𝑞 .
Обобщим на дерево. Нужно разбить дерево на куски диаметра не более 𝑘.
Это можно сделать или жадно одним dfs по дереву, или ткнув в 𝑛/𝑘 случайных вершин в
дереве и удалив их, или разбив на куски эйлеров обход дерева.
3. Дерево Штейнера
a) |𝑇 | = |𝑉 | ⇒ минимальное остовное дерево.
b) |𝑇 | = 2 ⇒ кратчайший путь между вершинами.
c) 𝑇 = {𝑎, 𝑏, 𝑐} ⇒ дерево имеет вид центр 𝑥, а из него пути в 𝑎, 𝑏, 𝑐.
Найдем Дейкстрой кратчайшие пути от 𝑎, 𝑏, 𝑐. Перебрем вершину 𝑥.
Еще у дерева может быть только два листа, переберем три кратчайших пути.
d) 𝑇 = {𝑎, 𝑏, 𝑐, 𝑑}. Деревья с < 4 листьями найдем перебором, какие, и применением предыдущих пунктов.
Если листьев 4, то есть один или два центра.
Запустим сначала Флойда. Теперь перебираем два центра 𝑥 и 𝑦 и смотрим 𝑑[𝑥, 𝑦]+𝑑[𝑎, 𝑥]+
10/11
Алгоритмы, весна 2019/20
Практика #9. Жадность, центроидная декомпозиция.
𝑑[𝑏, 𝑥] + 𝑑[𝑐, 𝑦] + 𝑑[𝑑, 𝑦].
Здесь нужно перебрать разбиения 𝑇 на пары.
e) |𝑇 | = 𝑘. Запустим сначала Флойда.
Динамика по подмножествам 𝑓 [𝑣, 𝐴, type].
𝑣 – корень дерева, которое мы строим.
𝐴 ⊆ [1..𝑘] – вершины, которые покрываем.
type = 0, если у 𝑣 один ребенок, иначе type = 1.
𝑓 – суммарный вес уже выбранных рёбер.
Если у 𝑣 один ребенок, то есть ближайшая 𝑢, в которой дерево ветвится. Перебираем 𝑢,
relax(𝑓 [𝑣, 𝐴, 0], 𝑓 [𝑢, 𝐴, 1] + 𝑑[𝑣, 𝑢]).
Иначе
перебираем,
какое
множество
𝐵
покроет
первый
ребенок:
relax(𝑓 [𝑣, 𝐴, 1], 𝑓 [𝑣, 𝐵, 0] + 𝑓 [𝑣, 𝐴 ∖ 𝐵, 1]).
Время 𝒪(𝑉 3 + 3𝑘 𝑉 + 2𝑘 𝑉 2 ).
Если не добавим параметр type, то граф переходов первого типа цикличен, считать
динамику не выйдет.
11/11
Скачать