Тверской государственный университет
Опубликован: 21.08.2007 | Доступ: свободный | Студентов: 3170 / 267 | Оценка: 4.08 / 3.92 | Длительность: 15:40:00
ISBN: 978-5-9556-0110-6
Специальности: Программист, Математик
Лекция 11:

Три алгоритма на графах

< Лекция 10 || Лекция 11: 1234

Поиск в глубину и задача о лабиринте

Задача поиска выхода из лабиринта известна с древних времен. В терминах графов ее можно формализовать так: лабиринт - это неориентированный граф, вершины которого представляют "перекрестки" лабиринта, а ребра - дорожки между соседними перекрестками. Одна или несколько вершин отмечены как выходы. Задача состоит в построении пути из некоторой исходной вершины в вершину-выход.

В этом разделе мы рассмотрим метод обхода всех вершин графа, называемый поиском в глубину. Его идею кратко можно описать так:

находясь в некоторой вершине v, идем из нее в произвольную еще не посещенную смежную вершину w, если такой вершины нет, то возвращаемся в вершину, из которой мы пришли в v.

Алгоритм поиска в глубину

Вход: G=(V, E) - неориентированный граф, представленный списками смежностей: для каждой v \in  V список Lv содержит перечень всех смежных с v вершин.

Выход: NUM[v] - массив с номерами вершин в порядке их прохождения и множество (древесных) ребер T \subseteq  E, по которым осуществляется обход.

Алгоритм ПОГ

  1. T = {}; NOMER = 1;
  2. для каждой вершины v \in  V положим NUM[v] = 0 и пометим v как "новую";
  3. ПОКА существует "новая" вершина v \in  V
  4. ВЫПОЛНЯТЬ ПОИСК(v).

Основную роль в этом алгоритме играет следующая рекурсивная процедура.

Алгоритм ПОИСК(v):

1.   пометить v как "старую";
2.   NUM[v] = NOMER;  NOMER = NOMER + 1;
3.   ДЛЯ КАЖДОЙ   w принадлежащей Lv   ВЫПОЛНЯТЬ
4.         ЕСЛИ   вершина   w   "новая"
5.            ТО
6.            { добавить (v, w)   к   T;
7.               ПОИСК(w);
8.            }

Теорема 11.2. Алгоритм ПОГ обходит (нумерует) все вершины графа G=(V,E). Если G - связный граф, то S=(V,T) - это остов G, если граф G не является связным, то S=(V,T) - это остовной лес для G, т.е. объединение остовных деревьев для каждой из компонент связности G.

Доказательство Первое утверждение следует из того, что по окончании алгоритма ПОГ все вершины графа старые, а это значит, что для каждой из них вызывалась процедура ПОИСК, которая в стр.2 присвоила номер.

Заметим теперь, что если ребро (v, w) попадает в T, то вызов процедуры ПОИСК(w) происходит после вызова ПОИСК(v) и поэтому NUM[v] < NUM[w]. Существование цикла в S означало бы, что для некоторого ребра из T это свойство нарушено (почему?). Следовательно, в S циклов нет.

Пусть G1=(V1,E1) - связная компонента G и v_{1} \in  V_{1} - первая ее вершина, для которой вызывается процедура ПОИСК. Тогда для каждой вершины w \in  V_{1} внутри вызова ПОИСК(v1) произойдет вызов ПОИСК(w).

Это утверждение доказывается индукцией по расстоянию ( длине кратчайшего пути ) от v1 до w.

Если это расстояние равно 1, то w \in  L_{v1} и рассматривается в вызове ПОИСК(v1) в стр.3. Если w в этот момент "старая", то, значит, ПОИСК(w) уже вызывался. Если же w "новая", то в стр. 7 происходит вызов ПОИСК(w).

Предположим теперь, что ПОИСК(u) вызывается для всех вершин u, находящихся на расстоянии k >= 1 от v1, и пусть вершина w \in  L\_ \{ v_{1}\} находится на рсстоянии (k + 1) от v1. Тогда имеется путь длины (k + 1) от v1 до w . Пусть u - это предпоследняя вершина на этом пути. Тогда расстояние от v1 до u равно k и по нашему предпроложению в некоторый момент выполняется вызов ПОИСК(u). Так как w \in  L_{u}, то в этом вызове вершина w в некоторый момент рассматривается в цикле в стр.3. Как и выше, если она в этот момент "старая", то ПОИСК(w) уже вызывался. Если же w еще "новая", то в стр.7 происходит вызов ПОИСК(w).

Также по индукции замечаем, что если вызов ПОИСК(w) произошел внутри вызова ПОИСК(v), то в T имеется путь из v в w. Следовательно, граф S1=(V1,T1), построенный в процессе вызова ПОИСК(v) является деревом с корнем v.

Дерево S=(V,T), которое строится алгоритмом ПОГ, называется глубинным остовом или глубинным остовным деревом графа G. Ребра, попавшие в множество T, называются прямыми, а не попавшие в это множество ребра из множества (E \ T) - обратными. Каждое обратное ребро (v,w) соединяет вершину v с ее предком w в глубинном остове (см. задачу 11.8). Поэтому в исходном графе G оно определяет цикл: от w к v по ребрам дерева T, а затем обратно от v к w по ребру (v,w). Поэтому алгоритм ПОГ можно использовать для проверки наличия циклов в G. Ребро (v,w) не добавляется к T, т.е. является обратным, тогда и только тогда, когда в стр.4 вызова ПОИСК(v) обнаруживается, что вершина w "старая". Поэтому, добавив в процедуру ПОИСК(v) последнюю строку

9.       ИНАЧЕ   ПЕЧАТЬ(v,w),

мы получим процедуру, которая в дополнение построению к глубинного остова графа будет распечатывать список всех обратных ребер. Если этот список не пуст, то в графе имеются циклы, иначе - нет.

Поиск в глубину позволяет обнаруживать не только циклы, но и многие другие важные части графов.

Определение 11.3. Ребро (v,w) неориентированного графа G=(V,E) называется мостом G, если при его удалении из E число связных компонент графа увеличивается, т.е. в графе G'=(V, E \ { (v,w)} связных компонент больше, чем в G.

Из этого определения, в частности, следует, что ребро является мостом тогда и только тогда, когда оно не входит ни в какой цикл ( почему?). Поиск в глубину позволяет находить все мосты графа. Во-первых, заметим, что любой мост (v,w) является ребром глубинного остова, так как другого пути, связывающего v и w нет. Во-вторых, если это ребро ориентировано от v к w, то в глубинном остове нет обратных ребер, соединяющих w и его потомки с предками w. Это условие является и достаточным, так как, если таких ребер нет, то удаление (v,w) нарушит связь между v и w и они окажутся в разных компонентах связности. Обозначим через ВЕРХ(w) минимум из NUM[w] и наименьшего из номеров вершин, к которым ведут обратные ребра от вершин поддерева Tw. Тогда, учитывая, что обратные ребра соединяют потомков с предками и что номера предков меньше номеров потомков, предложенный критерий можно переформулировать в следующем виде.

Теорема 11.3. Ребро (v,w) глубинного остова D=(V,E) неориентированного графа G=(V,E) является мостом G тогда и только тогда, когда ВЕРХ(w) > NUM[v] или, что эквивалентно, ВЕРХ(w) = NUM[w].

Вычисление значения ВЕРХ(w) можно организовать в процессе обхода в глубину, используя следующее соотношение:

ВЕРХ(w)= \min \{ \{NUM[w]\} \cup
\{\textrm{ВЕРХ}(z)\ |\ (v,z) - \textit{ прямое ребро  }\}\cup  \\ \cup  \{NUM[u] | (w,u) - \textit{ обратное ребро }\} \}

Для этого достаточно в строку 2 алгоритма ПОГ добавить начальное присвоение ВЕРХ(v) := NUM[v], в строке 7 приписать после ПОИСК(w) присвоение ВЕРХ(v) := min {ВЕРХ(v), ВЕРХ(w)}, учитывающее прямые ребра, и добавить строку

9.         ИНАЧЕ   ВЕРХ(v) := min{ВЕРХ(v),NUM(w)}

для учета обратных ребер.

Зная значения ВЕРХ(w), нетрудно выявить все мосты, используя критерий из теоремы 11.3.

Пример 11.2. Применим алгоритм ПОГ к графу G2, изображенному на рис. 11.3.

Граф G2

Рис. 11.3. Граф G2

Его представление в виде списков смежности имеет следующий вид:

\begin{array}{ll}
L_1:\ 6, 2 & L_7: 6, 8\\
L_2:\ 1, 9, 10, 3 & L_8: 6, 7\\
L_3:\  2, 5, 4 &  L_9: 2, 10, 11\\
L_4:\  3, 5 &     L_{10}: 2,9, 11 \\
L_5:\  2, 3, 4 &   L_{11}: 9, 10\\
L_6:\  1, 7, 8  &
\end{array}

Алгоритм ПОГ вызовет процедуру ПОИСК(1). Эта процедура рекурсивно вызовет ПОИСК(6) и т.д. Вот структура всех получающихся вызовов процедуры ПОИСК:

\begin{array}{ccccccc}
ПОИСК(1) &\Rightarrow& ПОИСК(6) &\Rightarrow& ПОИСК(7) &\Rightarrow& ПОИСК(8)\\ 
\Downarrow& & & & & &\\
ПОИСК(2) &\Rightarrow& ПОИСК(9) &\Rightarrow& ПОИСК(10) &\Rightarrow& ПОИСК(11)\\ 
\Downarrow& & & & & &\\
ПОИСК(3) &\Rightarrow& ПОИСК(5) &\Rightarrow& ПОИСК(4) & &\\
\end{array}

Вначале идут "горизонтальные" вызовы, затем возвраты справа налево и вызовы "по вертикали". В результате вершины G2 получат следующие номера, отражающие порядок их прохождения:

\begin{array}{rccccccccccc}
V  :     & 1 & 2& 3& 4& 5& 6& 7& 8& 9& 10 & 11\\
NUM :& 1 & 5& 9& 11& 10& 2& 3& 4& 6& 7 & 8
\end{array}

Ребра остова T, построенные в процессе обхода графа, показаны на рис. 11.4. Стрелки указывают направление обхода. В скобках рядом с номером вершины указан ее номер в массиве NUM, т.е. номер в порядке обхода алгоритмом ПОГ.

Остовное "глубинное" дерево S=(V,T) графа G2

Рис. 11.4. Остовное "глубинное" дерево S=(V,T) графа G2

В процессе построения этого дерева были определены следующие обратные ребра: (8,6), (10,2), (11,9), (5,2) и (4,3). Нетрудно проверить, что добавление любого из этих ребер к T приводит к образованию простого цикла.

Используя расширенный вариант ПОГ с вычислением функции ВЕРХ, мы получим следующий результат:

\begin{array}{rccccccccccc}
V  :                    & 1 & 2& 3& 4  & 5 & 6& 7& 8& 9& 10 & 11\\
NUM :& 1 & 5& 9& 11& 10& 2& 3& 4& 6& 7 & 8 \\
\textrm{ВЕРХ} :& 1 & 5& 5& 9  & 5 & 2& 2& 2& 5& 5 & 6 \end{array}

Так как ВЕРХ(2) =NUM[2] = 5 и ВЕРХ(6) =NUM[6] = 2, то по теореме 11.3 мостами графа G2 являются ребра (1,2) и (1,6) и других мостов у него нет.

Алгоритм поиска в глубину часто используется как основа для различных алгоритмов обработки графов. Вместо строки 6, в котрой вершина v получает номер NUM(v), можно вставить вызов любой процедуры, обрабатывающей информацию, связанную с этой вершиной (например, для задачи о лабиринте это может быть проверка того, что v является выходом из лабиринта). И тогда полученный вариант алгоритма обеспечит обработку всех вершин графа.

< Лекция 10 || Лекция 11: 1234
Елена Алексеевская
Елена Алексеевская

Это в лекции 3.

Татьяна Дембелова
Татьяна Дембелова

Почему в вводной лекции курса Основы дискретной математики одним из свойств отношения частичного порядка упоминается антирефлексивность? Посмотрела в других источниках, там -0  рефлексивность... http://ru.wikipedia.org/wiki/%D0%9E%D1%82%D0%BD%D0%BE%D1%88%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B0