![]() |
Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | |
|
В этом параграфе мы рассмотрим применение поиска в глубину к выделению 2-связных компонент графа. Здесь дело обстоит не так просто, как в предыдущей задаче. Конечно, можно было бы, удаляя поочередно вершины графа и каждый раз выделяя связные компоненты, найти его точки сочленения и блоки. Такой подход, однако, приводит к алгоритму сложности по крайней мере O( | EG|* | G|) Использование более глубоких свойств ПГ позволяет получить линейный по сложности алгоритм решения этой задачи.
В дальнейшем удобно использовать следующие термины. Пусть D=(V, А) —ориентированное дерево, х, у € V. Назовем х отцом вершины у, а у — сыном вершины х, если дуга (х, у) принадлежит А. Будем говорить, что вершины х и у сравнимы, если одна из них достижима из другой. Если при этом у достижима из х, то х — предок вершины у, а у — потомок вершины х. Подграф графа D, порожденный множеством, состоящим из вершины у и всех ее потомков, будем обозначать через Dv и называть поддеревом с корнем у.
Пусть в графе G проделан поиск в глубину из вершины v0 и получены остовное глубинное дерево Т и множество обратных ребер В.
Следующие три утверждения дают теоретическую основу для разработки эффективного алгоритма выделения двусвязных компонент.
Утверждение 74.1. Если дуга (х, у) принадлежит В, то х является потомком вершины у в Т.
Надо доказать, что вершина х принадлежит поддереву Ту. Предположим противное. Согласно утверждению 73.2 вершина х получает свой ПГ-номер позже, чем у. Поэтому присвоение вершине х ПГ-номера произойдет не раньше, чем будут посещены все вершины дерева Ту и произойдет возвращение в вершину s = F(y). Но возвращение в s не может произойти прежде, чем все вершины множества Ny получат ПГ-номера. Поскольку х € Ny и ПГ-номера к этому моменту не имеет, то получаем противоречие.
![]() |
Утверждение 74.2. Вершина vo является точкой сочленения графа G тогда и только тогда, когда она имеет не менее двух сыновей.
Пусть v0 — точка сочленения графа G. Ясно, что каждый блок графа, включающий вершину v0, содержит по крайней мере одного из ее сыновей.
Пусть теперь s1 , s2,..., sk — сыновья вершины v0. Рассмотрим поддеревья TSi (i = 1, k). Ясно, что VG — v0 = U VTSi. Для доказательства несвязности графа G — v0 достаточно показать, что в этом графе нет ребер, связывающих вершины различных TSi. Но это сразу следует из утверждения 74.1.
Будем говорить, что х — собственный предок (потомок) вершины у, если х — предок (потомок) у и х ≠ у.
Утверждение 74.3. Вершина v≠v0 является точкой сочленения графа G тогда и только тогда, когда для некоторого сына s этой вершины не существует дуги (х, у) € В такой, что х — потомок (не обязательно собственный) вершины s, а у — собственный предок вершины v.
Пусть v — точка сочленения графа G и G1, G2,..., Gm, m ≥ 2,— блоки этого графа, содержащие вершину v. Пусть, далее, v' = F(v), т. е. v' — отец вершины v. Не теряя общности считаем, что вершина v' содержится в блоке G1. Каждый из остальных блоков Gi(i = 2, m) должен, очевидно, содержать хотя бы одну вершину, являющуюся сыном вершины v. Пусть, например, s — сын
вершины v и s € G2. Если теперь допустить существование «обратного» ребра ab (т. е. дуги (а, b)€ В) такого, что а — потомок s, а b — собственный предок вершины v, то придем к существованию в графе G простого цикла,содержащего вершины v' и s. Этот цикл образован простой (а,b) -цепью, состоящей из «прямых» ребер и «обратного» ребра ab. Это означает (согласно утверждению 36.3), что вершины s и v' принадлежат одному блоку. Получили противоречие.
Докажем теперь вторую часть утверждения. Пусть вершина s является сыном вершины v, для которого выполняется условие, фигурирующее в формулировке утверждения. Это условие вместе с утверждением 74.1 означает, что если ab —«обратное» ребро и а € Та, то либо b € Та, либо b = v. Последнее означает, что все ребра графа G, связывающие вершины множества VTа с вершинами VG\VTа, инцидентны вершине v, т. е. v- —точка сочленения графа G.
Перейдем теперь непосредственно к разработке алгоритма выделения блоков графа. Чтобы уяснить схему применения ПГ к решению этой задачи, обратимся к примеру.На рис.74.1 изображен граф «с точностью до блоков». ПГ начинается в вершине v0. После нескольких шагов придем в одну из точек сочленения графа, например, в c2. Пусть, далее, выбирается и помечается как «прямое» ребро c2x блока В4. После этого дальнейшая работа ПГ вплоть до возвращения в c2 происходит точно так, как если бы было v0 = c2 и блоков В1, В2, В3 в графе G не было бы вовсе. Поэтому возвращение в Сг из х будет означать, что пройдены все ребра блоков В4 , В5, В6.,В7. Таким образом, возвращение в c2 произойдет позже, чем возвращения в c3 и c4 из висячих блоков В5, В6.,В7. Эти рассмотрения приводят к следующему важному выводу. Самое первое возвращение в точку сочленения произойдет сразу же после завершения обхода всех ребер некоторого висячего блока Вк. Это же справедливо и по отношению к дальнейшему поведению ПГ в графе, полученном из графа G удалением блока Bh.
Покажем, как использовать сказанное выше в предположении, что у нас есть способ, позволяющий при каждом возвращении из вершины v в F(v) определять, является ли F(v) точкой сочленения. С этой целью заведем стек S, в который будем заносить всякое ребро графа G сразу после получения им пометки «прямое» или «обратное». Таким образом, все ребра добавляются в конец списка S. Пусть в нашем примере возвращение из вершины у в c4 (см. рис. 74.1) является самым первым возвращением в точку сочленения. Тогда к моменту возвращения в c4 ребра блока В6 будут занимать все t последних мест в стеке S, где t — число ребер этого блока. Важно при этом, что ребро c4 у занимает первое среди t указанных мест. Это позволяет, просматривая стек S справа налево, выделить (т. е., например, переместить з отдельный список) все ребра блока В6. Затем эти ребра удаляются из S.
Итак, учитывая сказанное, необходимо уметь в процессе ПГ быстро определять возвращение в вершину, являющуюся точкой сочленения. Утверждения 74.2 и 74.3 дают соответствующие критерии, и нам надо их «алгоритмизировать». С этой целью для каждой вершины v € VG шределим множество P(v). В это множество включим вершину v и каждого ее предка w, для которого существует «обратное» ребро xw такое, что х — потомок вершины v в остовном глубинном дереве Т. Иными словами, множество P(v) состоит из всех предков вершины v, которых можно достичь из v, проходя сначала несколько (возможно, ни одной) дуг дерева Т, а затем одну дугу множества В.
Введем теперь функцию l(v), v € VG, полагая l(v) = min ПГ(x). Например, в графе на рис. 73.1 l (l) = 1, l (2) = 1, l (3) = l, l (4) = 3, l (5) = 1, l (6)=3, l (7)=3.
Используя функцию l(v), сформулируем утверждение 74.3 в следующем виде, более удобном для организации вычислений.
Утверждение 74.4. Вершина v≠v0 является точкой сочленения графа G тогда и только тогда, когда существует такой сын s этой вершины, что l(s)≥ ПГ (v).
![]() |
Справедливость этого соотношения становится очевидной, если заметить следующее. Множество предков вершины v, достижимых из нее с использованием дуг дерева Т и не более одной дуги из В, состоит из предков v, достижимых таким же способом из вершин s1, s2 ,..., sm и множества вершин, к которым ведут обратные ребра от вершины v.
Используя соотношение (1), функцию l можно вычислять попутно с выполнением обычных операций поиска в глубину. При первом посещении вершины v вместе с присвоением ПГ-номера полагаем l(v) = ПГ (v). В дальнейшем это значение корректируется в соответствии с формулой (1) следующим образом. Всякий раз, когда происходит возвращение в вершину v из некоторого ее сына s, полагаем l(v):=min{l(s), l(v)}. Кроме того, когда некоторое ребро vw помечается как «обратное», полагаем l(v):=min{l(v), ПГ (w)}. К моменту возвращения из v в вершину x=F(v) будет вычислено истинное значение l(v), которое в дальнейшем используется для корректировки l(х). Существенно, что каждая из этих корректировок требует только O (1) дополнительного времени. Поэтому ПГ вместе с вычислением функции l по-прежнему будет выполняться за время O( | EG|+ | G|).
Еще одна добавка к «стандартному» поиску в глубину связана с точками сочленения. Для обнаружения точки сочленения достаточно после каждого возвращения в вершину v из некоторого ее сына s сравнить величины l(s) и ПГ (v). Если окажется, что l(s) ≥ ПГ (v), то все ребра стека S, начиная с последнего и кончая sv, удаляются из этого списка. Удаленные ребра составляют один из блоков графа G. Согласно утверждению 74.4 неравенство l(s) ≥ ПГ (v) означает, что либо вершина v — точка сочленения, либо v = v0 и v не является точкой сочленения. Заметим, что второй случай не требует особого рассмотрения. В этом случае удаленные из стека S ребра соответствуют единственному блоку графа, содержащему v0. И, наконец, последняя деталь. Выделение блока графа G мы понимаем как удаление всех ребер этого блока из стека S. Можно считать, что одновременно с удалением из S каждое такое ребро заносится в некоторый другой список, причем множество ребер разных блоков разделены в этом списке, например, символом 0. Процедура построения этого нового списка очевидна, и чтобы не загромождать описания алгоритма, мы не приводимее в явном виде.
Сравнение l(s) с ПГ(v) производится |G| — 1 раз, и, следовательно, суммарное время, затраченное на выполнение сравнений, составляет O(|G|). Каждое ребро графа один раз включается в стек S и один раз исключается из него. Поэтому вся работа, связанная с изменением S, выполняется за время O(|EG|). Таким образом, поиск в глубину вместе с выделением блоков будет выполняться за время O( | EG|+ | G|).
Алгоритм A2 поиска в глубину с выделением двусвязных компонент.
1.ПГ(v0):=1, l(vo):= 1, S:=¢, F(v0):=0, T:=¢, В:= ¢, k:= 1 ,p:= 1, Q (1):= v0.
2 .v:=Q(p).
3.Просматривая список Nv, найти такую вершину w, что ребро vw не помечено, и перейти к п. 4. Если таких вершин нет, то перейти к п. 5.
4. Если вершина w имеет ПГ-номер, то поместить ребро vw как «обратное», занести ребро vw в стек S, l(v): = min{l(v), ПГ (w)} [выполнена корректировка l(v) ]. Перейти к п. 3 и продолжить просмотр списка Nv. Иначе ребро vw пометить как «прямое», k:= k + 1, ПГ (w):=k,l(w):=k, F(w):= v,p:=p + 1, Q(p):= w. Перейти к п. 2.
5. р:= р — 1. Если р = 0, то конец. Иначе перейти к п. 6.
6.Пусть x = F(v). Если l(v)> ПГ (x), то перейти к п. 7. Иначе l(x):= {l(x), l(v)} [выполнена корректировка 1{х) ]и перейти к п. 2.
7.Удалить из стека S все ребра вплоть до xv [удаленные ребра составляют блок графа G ]. Перейти к п. 2.
Пример. На рис. 74.2 изображен граф G и приведены списки смежности его вершин. Этот граф имеет четыре блока В1 , В2 , В3 , В4 и две точки сочленения d и х. Поиск в глубину начинается с вершины α, т. е. vo=α. На рис. 74.3 отражена ситуация, сложившаяся непосредственно перед выделением блока В4. К этому моменту шесть ребер помечены как «прямые» и одно как «обратное». Прямые ребра проведены жирными линиями, а обратное — пунктирной. Тем и другим придана соответствующая ориентация. Помеченные ребра расположены в стеке S в том порядке, в котором они получали пометки. Пара чисел (α, β), приписанная вершине v, имеет следующий смысл: α = ПГ (v), a β — значение l(v), вычисленное к рассматриваемому моменту.
![]() |
из вершины z в х обнаруживается, что l(z) = 5= ПГ(x). Следовательно, все ребра от tx до xz в стеке S составляют блок графа G. Эти ребра —tx, tz, xz — удаляются из S, и тем самым выделен блок В4..
После этого алгоритм работает так, как если бы блока В4. в графе G не было вообще. Ключевые моменты
![]() |
![]() |
В заключение отметим, что поиск в глубину оказывается полезным и при отыскании 3-связных компонент графа. Известен основанный на поиске в глубину алгоритм, решающий эту задачу за время O( | EG|+ | G|).
Дата публикования: 2015-01-23; Прочитано: 775 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!