Загрузил sosokulitki1990

Практика по алгоритмам, поиск в глубину (dfs)

Реклама
Первый курс, весенний семестр 2019/20
Практика по алгоритмам #1
Поиск в глубину (dfs)
17 января
Собрано 26 января 2020 г. в 00:28
Содержание
1. Поиск в глубину (dfs)
1
2. Разбор задач практики
2
3. Домашнее задание
3.1. Обязательная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Дополнительная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
5
4. Разбор домашнего задания
4.1. Обязательная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Дополнительная часть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
6
8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
Поиск в глубину (dfs)
1. Достижимость множеств
Даны два множества вершин: A и B, за O(V +E) проверить, есть ли путь из какой-нибудь
вершины a ∈ A в какую-нибудь вершину b ∈ B.
2. Циклы
a) Найти
b) Найти
c) Найти
d) Найти
e) Найти
f) Найти
цикл в орграфе через данное ребро за O(E).
цикл в орграфе через данную вершину за O(E).
в неориентированом графе какой-нибудь цикл за O(E).
цикл в неорграфе через данное ребро за O(E).
цикл в неорграфе через данную вершину за O(E).
в неориентированом графе какой-нибудь цикл за O(V ).
3. Гамильтонов путь
Дан ацикличный орграф, найти в нем гамильтонов путь за O(V +E).
4. Единственность топсорта
Дан ацикличный орграф, проверить единственность топсорта за O(V +E).
5. Ацикличная ориентация
Ориентировать неорграф так, чтобы он стал ацикличным, за O(V +E).
6. Сильносвязная ориентация
Ориентировать неорграф так, чтобы он стал сильносвязным, за O(V +E).
7. Нечетный цикл
За O(V +E) найти в неорграфе цикл нечетной длины.
8. Разделение на две клики
Разделить неорграф на две клики или проверить, что это невозможно, за O(V 2 ).
9. Разбиение на дружелюбные доли
У каждой вершины не более 3 врагов.
Разбить на 2 доли так, чтобы с вершиной в долю попало не более 1 врага. O(V +E).
10. Транзитивное замыкание
Дан орграф, построить матрицу достижимости. V, E 6 105 .
11. (*) Четный цикл
За O(V +E) найти в неорграфе цикл четной длины.
12. (*) Максимальное число различных циклов
Есть неорграф, нужно выбрать max число простых циклов так, чтобы каждый следующий
содержал хотя бы одно новое ребро. O(E).
1/8
Закончилась практика?
Отнеси лист на второй этаж в эко-мусорку
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
Разбор задач практики
1. Достижимость множеств
dfs из всех вершин A, проверить, что посещена хотя бы одна из B.
2. Циклы
a) Цикл в орграфе через ребро. e = (v, u), ищем путь из u в v.
b) Цикл в орграфе через вершину. Запускаем dfs из v, цикл есть ⇔ мы нашли в процессе
dfs ребро обратно в v.
Способ #2. Удалим вершину, найдем путь из ее исходящих соседей в ее входящих соседей.
Способ #3. Раздвоим вершину на vin и vout , все исходящие ребра проведем из vout , все
входящие в vin , найдем путь из vout в vin .
c) В неорграфе какой-нибудь цикл. dfs(v, parent), если нашли ребро в посещенную
вершину, не равную parent, то цикл. Когда в dfs(v, parent) нужно пойти в вершину u,
запускаем dfs(u, v).
d) Цикл в неорграфе через ребро. e = (v, u), ищем путь из u в v, не проходя по e. Это
просто запуск dfs(u, parent=v).
e) Цикл в неорграфе через вершину. Так же, как в орграфе, но запрещаем в dfs ходить
в предков.
f) В неорграфе какой-нибудь цикл за O(V ). В графе с V ребрами всегда есть цикл,
считаем только первые V ребер.
Но можно заметить, что стандартный способ с dfs тоже работает за O(V ). Пока мы не
нашли цикл, все посещенные dfs-ом ребра образуют дерево, итого мы упеем посмотреть
как раз только на V ребер.
3. Гамильтонов путь
Делаем topsort, проверяем, что из каждой вершины есть ребро в следующую.
4. Единственность топсорта
Делаем topsort, проверяем, что из каждой вершины есть ребро в следующую =)
И правда, если между какими-то соседями нет ребра, их можно поменять местами.
5. Ацикличная ориентация
Ориентируем ребра от меньшей вершины к большей.
Способ #2. Запустим dfs, ориентируем все ребра вниз, то есть ребра дерева и обратные из
предка в потомка.
В обоих случаях цикла нет, ибо на любом пути либо строго растет номер вершины, либо
глубина в дереве dfs.
6. Сильносвязная ориентация
Ориентируем ребра так, как на них впервые посмотрит dfs.
Получится, что ребра дерева dfs будут ориентированы вниз, а обратные вверх.
Из корня достижимо всё. Откуда угодно можно попасть в корень, потому что откуда угодно
можно подняться выше: если нельзя, то между поддеревом вершины и тем, что над ней, есть
только одно ребро, тогда ориентация была исходно невозможна.
7. Нечетный цикл
Красим граф в два цвета. Если видим ребро, ведущее из текущую вершину в уже покрашен2/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
ной в тот же цвет ҫ нашли нечетный цикл, он лежит на стеке рекурсии.
Если нет такой ситуации, покрасили в два цвета, нет нечетного цикла.
8. Разделение на две клики
Инвертируем все ребра: если между парой вершин нет ребра, добавим, иначе уберем. Теперь
надо разбить на два независимых множества, то есть на две доли, то есть покрасить в два
цвета.
Важное замечание: это работает за O(V 2 ), в инвертированном графе ребер V 2 − E.
9. Разбиение на дружелюбные доли
Разобьем как-нибудь. Метод локальных оптимизаций: если у какой-то вершины в её доле 2
врага, перекинем её в другую долю.
Каждый раз уменьшается суммарное число рёбер-врагов внутри долей, поэтому надо O(E)
шагов.
Чтобы быстро находить плохие вершины, сделаем это dfs-ом.
void dfs( int v ) {
if (bad(v)) {
color[v] ^= 1;
for (int x : g[v]) dfs(x);
}
}
for (int v = 0; v < n; v++)
dfs(v);
Заметим, что тут нет пометок посещенных вершин, но рекурсивные вызовы возникают только после переркидывания вершины, поэтому время O(V + E).
10. Транзитивное замыкание
Сконденсируем граф. Из каждой вершины достижима ее ксс, нужно узнать, что еще.
Храним bitset вершин, достижимых из данной. Делаем dfs, ответ для вершины ҫ OR bitset’ов
ее детей.
11. Чётный цикл
Мы умеем разбивать кактус на циклы. Если наш граф ҫ кактус, алгоритм успешно отработает за O(V + E) и нам останется проверить чётности найденных циклов. Если наш граф
не кактус, то алгоритм найдёт в какой-то момент два пересекающихся по ребру цикла. Заметим, что или один из этих двух циклов чётный, или они оба нечётные, но благодаря их
пересечению мы можем выделить чётный.
12. Максимально число различных циклов
Рассмотрим все циклы, образованные обратными ребрами dfs.
3/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
Домашнее задание
3.1. Обязательная часть
1. (2) Покраска в 4 цвета
За O∗ (2n ) проверить, можно ли покрасить граф в 4 цвета.
Подсказка: в два цвета красить очень просто.
2. (2) Минимизация максимального ребра на цикле
Дан неорграф с целыми положительными весами на рёбрах. Найти в неорграфе такой цикл,
что максимальный вес ребра этого цикла минимален. O((V +E) log E).
Решить, используя только известное нам.
3. (2) Разноцветные двери
Есть комнаты и двери между комнатами. Нужно каждую дверь покрасить с одной стороны
в зеленый цвет, с другой в оранжевый цвет так, чтобы для каждой комнаты количества
зеленых и оранжевых дверей в комнате отличались не более чем на один.
Решить за время O(polynom(V, E)), (+1) O(V +E).
4. (2) Ещё один вариант разбиения на две доли
Разбить множество вершин неорграфа на две доли так, чтобы у каждой вершины был сосед
в другой доле. O(V +E).
5. (3) Ромбики
Найти в неорграфе ҡромбик с диагональюә: 4 вершины a, b, c, d с 5 рёбрами ab, bc, cd, da, ac.
Оценка: (1) O(V 3 ), (1) O(V E), (1) O( VwE ), (+1) O(E 3/2 ).
6. (3) Покраска в 3 цвета
Дан изначально пустой неорграф. В него добавляются рёбра и вершины. При этом поддерживается инвариант, что степени всех вершин не более 5. Поддерживать покраску вершин
в 3 цвета так, чтобы у каждой было не более одного соседа того же цвета. При добавлении
новых ребра/вершины обновлять покраску за амортизированное O(1).
4/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
3.2. Дополнительная часть
1. (3) Минимизация максимальной исходящей степени
Дан неорграф. Ориентировать его так, что максимальная исходящая степень была минимальна. O(E 2 ). Можно еще на полилог.
2. (3) Сильная связность
Сильная связность (задача с доп практики). Решение за O(V +E): построим конденсацию,
выделим стоки и истоки. Затем найдем за O(V +E) максимальное по включению множество
непересекающихся по вершинам путей из истоков в стоки. То есть, не существует еще одного
пути из истоков в стоки, не пересекающегося с уже выбранным. Пусть i-й путь начинается
в ai , заканчивается в bi , всего путей k. Добавим ребра (b1 , a2 ), (b2 , a3 ), . . . , (bn , a1 ). Это неполное описание решения. Задача в том, чтобы довести его до конца, доказать корректность,
доказать линейность времени работы.
3. (3) Существование пути
Напишите детерминированное решение, которое имеет доступ к оракулу g(i, j) ҫ есть ли
ребро между i и j, и должно, используя полилогарифм от n памяти проверить наличие пути
из a в b в графе из n вершин.
5/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
Разбор домашнего задания
4.1. Обязательная часть
1. Покраска в 4 цвета
Перебираем A за 2n и за O(n + m) проверяем, можно ли множества A и A покрасить в два
цвета (dfs).
2. Минимизация максимального ребра на цикле
Сортировка весов ребер, бинарный поиск по этому массиву, dfs для проверки наличия цикла,
использующий только ребра веса 6 mid.
3. Разноцветные двери
Переформулируем: нужно ориентировать ребра неорграфа так, чтобы разница между входящей и выходящей степенью вершины не превысила 1.
Пока есть цикл, находим его и ориентируем ребра вдоль него, это не меняет разность. Забываем про эти ребра.
Останется набор деревьев. Пока граф не пуст, ищем путь из одной висячей в другую, ориентируем вдоль пути.
Время O(E 2 ), на каждом шаге избавились хоть от одного ребра.
O(V + E). Проходим по вершинам нечетной степени, из каждой строим путь dfs-ом, не
запоминающим вершины. Пройденные ребра ориентируем в порядке прохода и забываем.
Если построили из v в u и из u больше некуда идти. Тогда у v теперь четная степень, у
промежуточных вершин разность не изменилась. В u вошли на один раз больше, чем вышли,
и больше трогать не будем.
Теперь остались вершины только четной степени, делаем то же самое, но теперь путь всегда
будет кончаться там же, где начался, так как из остальных вершин всегда можно выйти,
если вошли.
4. Ещё один вариант разбиения на две доли
Запустим dfs, вершины с четной глубиной в дереве dfs пойдут в первую долю, с нечетной ҫ
во вторую. Предок каждой вершины в другой доле. У корней dfs либо дети в другой доле,
либо они изолированы, тогда ничего не поделать.
Способ #2. Разобьём сперва как-нибудь. Перебираем вершины. Если у какой-то вершина
соседи только в своей доле, перекинем её в другую долю. Это сделает лучше ей и ее соседям,
для остальных вершин ничего не изменится. O(V + E).
5. Ромбики
Основная идея: переберём ребро (a, b), диагональ ромба.
O( VwE ): храним соседей каждой вершины в bitset,
проверка ҫ (c[a] & c[b]).count() >= 2.
6. Покраска в 3 цвета
Добавилось ребро (v, u), пусть у v теперь два соседа ее цвета. Перекрасим v в такой c, что у
нее не больше одного соседа цвета c. Он найдется, ведь цветов 3, а соседей не более 5.
6/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
У v теперь может появиться такой сосед w цвета c, что у w два соседа цвета c. Запускаем
процесс исправления конфликтов от w.
При каждом исправлении вершины уходят два одноцветных ребра, появляется не более одного. То есть хотя бы на одно одноцветное ребро становится меньше при обработке каждой
вершины. Потенциал ҫ число одноцветных ребер.
7/8
Алгоритмы, весна 2019/20
Практика #1. Поиск в глубину (dfs).
4.2. Дополнительная часть
1. Основная идея: если есть путь из вершины v в вершины u, что степень v хотя бы на 2 больше
степени u, то инвертирование пути улучшит ситуацию.
Начальное разбиение можно задать как угодно.
2. ?
3. bool has_path(v, u, len) {
if (len == 1)
return g(v, u);
len1 = len / 2;
len2 = len - len1;
for (mid = 0; mid < n; ++mid)
if (has_path(v, mid, len1) and has_path(mid, u, len2))
return true;
return false;
}
Откуда взять len? Перебрать или просто добавить петлю на конечной вершине.
8/8
Powered by TCPDF (www.tcpdf.org)
Скачать