# теория · шаг 3 из 7
Сильная связность и конденсация: любой граф - это ДАГ из кусков
Коротко
В ориентированном графе две вершины сильно связаны, если из каждой достижима другая. Это отношение эквивалентности, поэтому оно разбивает вершины на непересекающиеся компоненты сильной связности (КСС): внутри компоненты можно ходить откуда угодно куда угодно, между компонентами - только в одну сторону. Если стянуть каждую компоненту в одну точку, получится конденсация, и она ВСЕГДА ациклична - цикл между компонентами означал бы, что они на самом деле одна. Отсюда главный структурный факт раздела: любой ориентированный граф - это ДАГ, склеенный из сильно связных кусков, и потому к нему после конденсации применимо всё, что мы умеем для ДАГов, включая топологическую сортировку.
Если ты знаешь определение сильной связности, умеешь строить конденсацию и можешь доказать, что она ациклична, листай до «Теперь сам».
Как думаешь, что делать с циклом в зависимостях
Система сборки нашла цикл: модуль A зависит от B, B от C, C от A. Топологического
порядка нет. Прежде чем читать дальше, подумай: значит ли это, что дальше работать нельзя? И что
осмысленного можно сказать про такой граф - ведь остальные-то модули в цикл не входят и их порядок
очевиден.
На что это похоже
Города и односторонние дороги. Внутри центра можно проехать от любого перекрёстка к любому - сколько угодно петляя. Но из центра в спальный район дорога есть, а обратно нет. Стянем центр в одну точку, район в другую - получится простая схема со стрелками в одну сторону, без колец. Так устроен любой город с односторонним движением: кольца - внутри районов, а между районами всегда есть направление.
Механизм: отношение, разбиение, конденсация
u ~ v ⟺ есть путь u → ... → v И есть путь v → ... → u
это отношение эквивалентности:
рефлексивно - из вершины в неё саму путь длины ноль есть всегда
симметрично - условие записано симметрично
транзитивно - пути склеиваются
значит вершины разбиваются на классы - компоненты сильной связности
Компонента из одной вершины - не вырожденный случай, а самый частый: если вершина не лежит ни на
одном цикле, её компонента состоит из неё одной. В ациклическом графе КСС ровно V штук.
Конденсация строится так: каждую компоненту заменяем одной вершиной; ребро между компонентами проводим, если в исходном графе было хоть одно ребро из какой-нибудь вершины первой в какую-нибудь вершину второй (кратные рёбра схлопываем, петли выбрасываем).
Правило
Вершины u и v сильно связаны, если достижимы друг из друга; это эквивалентность, и она
разбивает граф на компоненты сильной связности. Компонента из одной вершины - обычное дело: в
ациклическом графе компонент ровно V. Конденсация (каждая компонента - одна вершина) ВСЕГДА
ациклична, поэтому любой ориентированный граф представим как ДАГ из сильно связных кусков, к
которому применима топологическая сортировка.
Разбор: находим компоненты руками
Граф: a→b, b→c, c→a, c→d, d→e, e→d, d→f.
Проверяем попарную достижимость. Из a в b - прямо; из b в a - через c (b→c→a). Значит
a ~ b. Аналогично a ~ c. Компонента {a, b, c} - это цикл.
d и e: d→e и e→d - сильно связаны, компонента {d, e}.
f: из f рёбер нет вовсе, значит вернуться из неё никуда нельзя - компонента {f} из одной
вершины. Заметь: d→f есть, а обратного пути нет, поэтому d и f в разных компонентах.
Итого три компоненты: {a,b,c}, {d,e}, {f}. Конденсация: три вершины и рёбра {a,b,c} →
{d,e} (из-за c→d) и {d,e} → {f} (из-за d→f). Циклов в ней нет, топологический порядок -
{a,b,c}, {d,e}, {f}.
И вот практический вывод для задачи из начала урока: система сборки, нашедшая цикл, не обязана сдаваться. Она может стянуть каждый цикл в группу, отсортировать ГРУППЫ топологически и сказать честно: «вот эти три модуля придётся собирать вместе, а всё остальное - в таком порядке». Это куда полезнее, чем «обнаружена циклическая зависимость».
Разбор: почему конденсация ациклична
Докажем от противного. Пусть в конденсации есть цикл из компонент C₁ → C₂ → ... → C_k → C₁, и
пусть k >= 2 (петли мы выбросили).
Ребро C_i → C_{i+1} означает, что в исходном графе есть ребро из какой-то вершины C_i в
какую-то вершину C_{i+1}. Значит из ЛЮБОЙ вершины C_i можно добраться до любой вершины
C_{i+1}: внутри C_i дойдём до начала ребра (компонента сильно связна), перейдём по ребру, а
внутри C_{i+1} дойдём куда угодно. Пройдя по всему циклу компонент, получаем: из любой вершины
C₁ достижима любая вершина C₂, и наоборот - из C₂ через остальные компоненты обратно в C₁.
Но это в точности определение сильной связности: значит вершины C₁ и C₂ лежат в ОДНОЙ
компоненте. Противоречие - мы считали их разными. Следовательно цикла в конденсации нет.
Обрати внимание на приём: доказательство не про алгоритм, а про определение. Именно поэтому результат такой прочный - он верен для любого графа, независимо от того, как мы будем искать компоненты.
Что ломается без этого
Первое: путать сильную связность со связностью «если забыть направления» (её называют слабой).
Граф a→b, c→b слабо связен, но сильных компонент в нём три - из b никуда не уйти. Вторая
ошибка - считать, что компоненты можно найти простым обходом: обход из вершины даёт ДОСТИЖИМЫЕ
вершины, а нужны те, что достижимы взаимно; наивный способ требует запускать обход из каждой
вершины и пересекать множества - O(V·(V+E)), и на больших графах это неприемлемо (следующий урок
- как за O(V + E)). Третье: забывать про компоненты из одной вершины и удивляться, что их
большинство. Четвёртое: ОСТАВЛЯТЬ при конденсации рёбра, которые превращаются в петли (то есть
рёбра внутри одной компоненты), - тогда «ациклическая» конденсация окажется с петлями. Их
выбрасывают; а если факт «внутри компоненты есть цикл» нужен по смыслу задачи, его отмечают
признаком у вершины, а не ребром. Пятое: думать, что конденсация - это «упрощение графа»: она теряет внутреннюю структуру
компонент, и восстановить по ней исходный граф нельзя.
Зачем это в работе
Первое и самое частое - внятные сообщения о циклических зависимостях: вместо «цикл найден» система показывает группу модулей, которые завязаны друг на друга, и порядок остальных. Компиляторы так находят взаимно рекурсивные функции (они образуют одну КСС в графе вызовов) - это нужно, чтобы компилировать их вместе и правильно выводить типы. Анализ веб-графа: классическое исследование строения интернета описало его как «бабочку» - большая центральная КСС, из которой ведут страницы «в неё» и «из неё». В задаче 2-SAT (выполнимость формул с парами ограничений) ответ читается прямо из компонент сильной связности графа импликаций - это самый известный «неочевидный» пример. Обнаружение взаимных блокировок и анализ достижимости в больших системах тоже начинаются с конденсации: после неё граф становится ДАГом, и дальше работают быстрые алгоритмы на ДАГах.
Теперь сам
Граф: 1→2, 2→3, 3→1, 3→4, 4→5, 5→6, 6→4, 2→6. Найди компоненты сильной связности,
построй конденсацию и выпиши её топологический порядок.
Ответ. Ищем взаимную достижимость. Вершины 1, 2, 3: 1→2→3→1 - цикл, значит все три в одной
компоненте {1,2,3}. Вершины 4, 5, 6: 4→5→6→4 - тоже цикл, компонента {4,5,6}. Могут ли эти
шесть вершин быть одной компонентой? Из {1,2,3} в {4,5,6} попасть можно (3→4 или 2→6), а
обратно - посмотрим рёбра из 4, 5, 6: 4→5, 5→6, 6→4 - все ведут внутрь своей компоненты.
Значит вернуться нельзя, и компоненты две: {1,2,3} и {4,5,6}. Конденсация: две вершины и
ребро из {1,2,3} в {4,5,6} - причём ребро ОДНО, хотя в исходном графе таких рёбер было два
(3→4 и 2→6): кратные рёбра между компонентами схлопываются. Топологический порядок
конденсации: {1,2,3}, затем {4,5,6}, и он единственный. Проверь себя вопросом: сколько
компонент было бы, добавь мы ребро 6→2? Тогда из {4,5,6} стало бы можно вернуться в {1,2,3},
все шесть вершин слились бы в ОДНУ компоненту, а конденсация превратилась бы в единственную точку
без рёбер.
Главное
Две вершины ориентированного графа сильно связаны, если достижимы друг из друга. Это отношение
эквивалентности, поэтому граф разбивается на компоненты сильной связности - внутри компоненты
ходить можно как угодно, между компонентами только в одну сторону. Компонента из одной вершины -
норма, а не вырождение: в ациклическом графе их ровно V. Стягивание каждой компоненты в точку
даёт КОНДЕНСАЦИЮ, и она всегда ациклична: цикл между компонентами означал бы взаимную достижимость,
то есть что это одна компонента. Отсюда общий взгляд: любой ориентированный граф - ДАГ, склеенный
из сильно связных кусков, и после конденсации к нему применимы топологическая сортировка и всё
остальное, что работает на ДАГах. Не путай сильную связность со слабой (когда направления
игнорируют): a→b, c→b слабо связен, но сильных компонент там три. Наивный поиск компонент
стоит O(V·(V+E)); как уложиться в O(V + E) - следующий урок.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий