Опубликован: 05.01.2015 | Уровень: для всех | Доступ: платный
Лекция 18:

Поиск на графе

Часто изучение свойств графа выполняется с помощью систематического просмотра каждой его вершины и каждого ребра. Определение некоторых простых свойств — например, вычисление степеней всех его вершин — выполняется просто перебором всех ребер (в любом порядке). Многие другие свойства графа связаны с путями на графах, поэтому они естественно определяются с помощью переходов от одной вершины к другой вдоль ребер графа. Эту базовую абстрактную модель используют почти все рассматриваемые нами алгоритмы обработки графов. В данной главе мы рассматриваем фундаментальные алгоритмы поиска на графах (graph search), которые используются для перемещения по графам с попутным изучением его структурных свойств.

Поиск на графе в таком виде эквивалентен исследованию лабиринта: коридоры лабиринта соответствуют ребрам графа, а места пересечения коридоров соответствуют вершинам графа. Когда программа меняет значение переменной с вершины v на вершину w из-за наличия ребра v-w, такое изменение можно рассматривать как переход в лабиринте из точки v в точку w. Мы начинаем данную главу с изучения систематического обхода лабиринтов. Это поможет нам наглядно представить, как базовые алгоритмы поиска на графах проходят через каждое ребро и каждую вершину графа.

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

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

В качестве иллюстрации применения этих базовых методов поиска на графах для решения более сложных задач мы рассмотрим алгоритмы поиска связных компонентов, двусвязных компонентов, остовных деревьев и кратчайших путей, а также алгоритмы решения множества других задач обработки графов. Эти реализации наглядно продемонстрируют подход, который будет использован для решения более трудных задач в лекциях 19—22.

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

Исследование лабиринта

Поиск на графах иногда удобно рассматривать в терминах эквивалентной задачи, которая имеет долгую и интересную историю (см. раздел ссылок) — задачи поиска выхода из лабиринта, который состоит из перекрестков, соединенных коридорами. В этом разделе представлен подробный анализ базового метода исследования каждого коридора в любом заданном лабиринте. В некоторых лабиринтах достаточно одного простого правила, однако для большинства лабиринтов необходима более сложная стратегия (см. рис. 18.1). Использование терминов лабиринт вместо граф, коридор вместо ребро и перекресток вместо вершина — просто семантическое различие, однако оно поможет глубже прочувствовать задачу.

Исследование лабиринта

Рис. 18.1. Исследование лабиринта

Простой лабиринт можно полностью обойти, руководствуясь простым правилом " держитесь правой рукой за стену " . Это правило позволяет обойти весь лабиринт, который изображен в верхней части рисунка, пройдя по каждому коридору один раз в каждом направлении. Но если воспользоваться этим правилом для обхода лабиринта, содержащего цикл, мы вернемся в начальную точку, так и не побывав во всех местах лабиринта, как показано в нижней части рисунка.

Один из приемов исследования лабиринта без риска заблудиться известен еще с античных времен (как минимум, со времени легенды о Тесее и Минотавре) — он заключается в том, чтобы разматывать клубок по мере продвижения вглубь лабиринта. Нить клубка гарантирует, что мы всегда сможем выбраться из лабиринта, но, кроме этого, нам хотелось бы наверняка побывать в каждой части лабиринта и не проходить без необходимости по уже пройденному пути. Для этого нужно какое-то средство, позволяющее помечать те места, в которых мы уже были. В качестве такого средства годится и нить, однако мы воспользуемся другим методом, который больше похож на компьютерную реализацию.

Допустим, что на каждом перекрестке установлены лампы, которые сначала выключены, а в обоих концах каждого коридора имеются двери, которые в исходном состоянии закрыты. Допустим также, что в дверях имеются окна, лампы достаточно мощные, а коридоры достаточно прямые, так что, открыв дверь, можно увидеть, освещен или нет перекресток на другом конце коридора (даже если дверь на другом конце коридора закрыта). Наша цель заключается в том, чтобы зажечь все лампы и открыть все двери. Для достижения этой цели нужен набор правил, которым мы будем систематически следовать. Следующая стратегия исследования лабиринта, которую мы будем называть методом Тремо (Tremaux exploration), известна, по меньшей мере, с девятнадцатого столетия (см. раздел ссылок):

  • Если на текущем перекрестке нет закрытых дверей, перейдите к шагу 3. Иначе откройте любую дверь любого коридора, ведущую из текущего перекрестка (и оставьте ее открытой).
  • Если вы видите, что лампа, установленная на перекрестке на другом конце этого коридора уже включена, попробуйте открыть другую дверь на текущем перекрестке (шаг 1). Иначе (если перекресток на другом конце коридора не освещен), пройдите по коридору к этому перекрестку, разматывая при этом нить, включите свет и перейдите к шагу 1.
  • Если все двери на текущем перекрестке открыты, проверьте, находитесь ли вы в отправной точке. Если да, то процесс окончен. Если нет, воспользуйтесь нитью, чтобы вернуться назад по коридору, который привел вас в этот перекресток в первый раз, сматывая нить по мере продвижения, и ищите другую закрытую дверь уже там (т.е. вернитесь к шагу 1).

На рис. 18.2 и 18.3 представлен пример обхода графа и показано, что в данном случае, действительно, все лампы зажжены и все двери открыты. На них показан один из множества возможных успешных исходов исследования, ведь на каждом перекрестке можно открывать двери в любом порядке. Полезное упражнение — убедиться методом математической индукции, что этот метод эффективен всегда.

Лемма 18.1. При обходе лабиринта методом Тремо мы зажигаем все лампы и открываем все двери в лабиринте и завершаем обход там, где его начали.

Доказательство. Докажем это утверждение по индукции. Вначале отметим, что оно выполняется в тривиальном случае, т.е. в лабиринте, который содержит один перекресток и ни одного коридора — мы просто включаем свет. Для любого лабиринта, который содержит более одного перекрестка, мы полагаем, что это свойство справедливо для всех лабиринтов с меньшим числом перекрестков. Достаточно показать, что мы посетили все перекрестки, поскольку мы открываем все двери на каждом посещенном перекрестке. Теперь рассмотрим первый коридор, выбранный на первом перекрестке, и разделим все перекрестки на два подмножества ( рис. 18.4): (1) те, которые мы можем достичь, выбрав этот коридор и не возвращаясь в исходную точку, и (2) те, которые мы не можем достичь, не вернувшись в исходную точку. По индуктивному предположению мы знаем, что посетили все перекрестки в (1) (игнорируя все коридоры, ведущие к исходному освещенному перекрестку) и вернулись на исходный перекресток. Тогда, применяя индуктивное предположение еще раз, мы знаем, что посетили все перекрестки (игнорируя коридоры, ведущие из отправной точки на перекрестки в (2), которые освещены). $\blacksquare$

Из подробного примера, представленного на рис. 18.2 и рис. 18.3, мы видим, что при выборе очередного коридора возможны четыре различные ситуации:

  • Коридор не освещен, следовательно, мы выбираем его.
  • Коридор уже был пройден (и в нем размотана нить), и мы возвращаемся по нему (сматывая нить).
  • Дверь на другом конце коридора закрыта (но сам перекресток освещен), поэтому мы пропускаем этот коридор.
  • Дверь на другом конце коридора открыта (и перекресток освещен), поэтому мы пропускаем этот коридор.

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

Далее мы увидим, как этот способ исследования лабиринта преобразуется непосредственно в поиск на графе.

 Пример применения метода Тремо для конкретного лабиринта

Рис. 18.2. Пример применения метода Тремо для конкретного лабиринта

На этой диаграмме места, которые мы еще не посетили, заштрихованы (темные), а те места, в которых мы уже были, не заштрихованы (светлые). Мы полагаем, что на перекрестках горит свет, и что когда двери открыты с обоих концов коридора, этот коридор освещен. Исследование лабиринта мы начинаем с перекрестка 0 и выбираем коридор к перекрестку 2 (вверху слева). Далее мы продвигаемся по маршруту 6, 4, 3 и 5, по мере продвижения открывая двери в коридоры, зажигая свет на перекрестках и разматывая нить (слева). Открыв дверь, которая ведет из 5 в 0, мы видим, что перекресток 0 освещен, и поэтому игнорируем этот коридор (вверху справа). Аналогично, мы пропускаем коридор от 5 к 4 (справа, вторая диаграмма сверху), и нам остается только вернуться из 5 в 3 и далее в 4, сматывая нить в клубок. Когда мы откроем дверь коридора, ведущего из 4 в 5, мы видим через открытую дверь на другом конце коридора, что перекресток 5 освещен, и поэтому пропускаем этот коридор (справа внизу). Мы не прошли по коридору, соединяющему перекрестки 4 и 5, но мы осветили его, открыв двери с обоих концов.

 Пример применения метода Тремо для конкретного лабиринта (продолжение)

Рис. 18.3. Пример применения метода Тремо для конкретного лабиринта (продолжение)

Далее мы продвигаемся к перекрестку 7 (слева вверху), открываем дверь и видим, что перекресток 0 освещен (слева, вторая диаграмма сверху), после чего проходим к 1 (слева, третья диаграмма сверху). В этой точке большая часть лабиринта уже пройдена, и мы с помощью нити возвращаемся в начало пути, двигаясь от 1 до 7, далее до 4, до 6, до 2 и до 0. Вернувшись на перекресток 0, мы завершаем исследование, проверив коридоры, ведущие к перекрестку 5 (справа, вторая диаграмма снизу) и к перекрестку 7 (внизу справа), после чего все коридоры и перекрестки становятся освещенными. Здесь также коридоры, соединяющие перекрестки 0 с 5 и 0 с 7, освещены потому, что мы открыли двери с обоих концов, хотя и не проходили по ним.

 Разбиение лабиринта

Рис. 18.4. Разбиение лабиринта

Для доказательства методом индукции, что метод Тремо приводит во все точки лабиринта (вверху), мы разбиваем его на две части меньших размеров, удалив все ребра, соединяющие первый перекресток с любым другим перекрестком, который можно достичь из первого коридора, не возвращаясь через первый перекресток (внизу).

Упражнения

18.1. Предположим, что из лабиринта, показанного на рис. 18.2 и рис. 18.3, удалены перекрестки 6 и 7 (а также все ведущие к ним коридоры), зато добавлен коридор, который соединяет перекрестки 1 и 2. Покажите обход полученного лабиринта методом Тремо в стиле рис. 18.2 и рис. 18.3.

18.2. Какая из представленных ниже последовательностей не может быть последовательностью включения ламп при обходе методом Тремо лабиринта, представленного на рис. 18.2 и 18.3?

0-7-4-5-3-1-6-2

0-2-6-4-3-7-1-5

0-5-3-4-7-1-6-2

0-7-4-6-2-1-3-5

18.3. Сколько существует различных путей обхода методом Тремо лабиринта, показанного на рис. 18.2 и рис. 18.3?

Бактыгуль Асаинова
Бактыгуль Асаинова

Здравствуйте прошла курсы на тему Алгоритмы С++. Но не пришел сертификат и не доступен.Где и как можно его скаачат?

Александра Боброва
Александра Боброва

Я прошла все лекции на 100%.

Но в https://www.intuit.ru/intuituser/study/diplomas ничего нет.

Что делать? Как получить сертификат?

Александр Ефимов
Александр Ефимов
Россия, Спб, СпбГтурп
Павел Сусликов
Павел Сусликов
Россия