- •В. Н. Степанов дискретная математика: графы и алгоритмы на графах
- •Предисловие
- •1. Основные понятия теории графов
- •1.1. Граф и его разновидности
- •1.2. Морфизмы графов
- •1.3. Степени вершин
- •1.4. Маршруты, цепи, циклы, связность
- •1.5. Операции над графами
- •1.6. Примеры графов
- •1.7. Метрические характеристики графов
- •1.8. Представления графов
- •2. Алгоритмы и сложность
- •2.1. Понятие алгоритма
- •2.2. Сложность алгоритма
- •2.3. Запись алгоритма
- •3. Обходы графов
- •3.1. Поиск в глубину на графе
- •3.2. Поиск в ширину на графе
- •3.3. Алгоритм выделения компонент связности
- •4. Деревья
- •4.1. Деревья. Свойства деревьев
- •4.2. Остовы. Теорема Кирхгофа
- •4.3. Теорема Кэли
- •4.4. Фундаментальная система циклов. Цикломатическое число
- •4.5. Алгоритм отыскания фундаментального множества циклов на графе
- •5. Остов минимального веса. Алгоритм Краскала и Прима
- •5.1. Алгоритм д. Краскала
- •5.2. Алгоритм р. Прима
- •6. Кратчайшие пути между вершинами графа
- •6.1. Алгоритм Дейкстры
- •6.2. Алгоритм Флойда
- •7. Эйлеровы графы
- •7.1. Теорема Эйлера
- •7.2. Алгоритм Флёри
- •8. Гамильтоновы графы
- •8.1. Гамильтоновы маршруты. Задача коммивояжера
- •8.2. Существование гамильтоновых маршрутов
- •9. Алгоритмы отыскания гамильтоновых циклов
- •9.1. Алгоритм с возвратом (полного перебора)
3. Обходы графов
При решении прикладных задач часто возникает необходимость обхода вершин графа, связанная с поиском вершины, удовлетворяющей определенным свойствам. Обход графа – это некоторое систематическое перечисление его вершин (и/или ребер). Обычно обход по графу сопровождается нумерацией вершин графа в том порядке, в котором они отмечаются, а также определенной маркировкой ребер (или дуг) графа. Из обходов графа наиболее известны поиск в глубину и поиск в ширину, использующие локальную информацию (списки смежности вершин). Алгоритмы поиска в глубину и ширину лежат в основе многих конкретных алгоритмов на графах. Опишем стратегии поиска в глубину и ширину.
3.1. Поиск в глубину на графе
Поиск в глубину осуществляется следующим образом. Пусть поиск начинается с некоторой начальной вершины и мы достигли некоторой вершины (в начале процедуры ). Отмечаем вершину и просматриваем вершины из ее списка смежности (т. е. элементы множества ). Если в этом списке существует хотя бы одна неотмеченная вершина, то идем из первой вершины списка по ребру – «ныряем» вглубь, откладывая анализ других элементов списка «на потом» (в случае ориентированного графа, находясь в вершине , следует выбирать только дугу , выходящую из вершины ). Если же в списке неотмеченных вершин нет, то возвращаемся из вершины в вершину , из которой в нее попали, и исследуем список смежности вершины . Процедура заканчивается, когда вернемся в начальную вершину и все вершины окажутся отмеченными, либо окажется, что неотмеченные вершины есть, но они несмежные с вершиной . В последнем случае возможно продолжение поиска из новой вершины или остановка. Для связного графа описанная процедура определяет единственный обход графа, а в случае несвязного графа – его компоненту, содержащую вершину . Для получения полного обхода несвязного графа необходимо начинать процесс в каждой связной компоненте. С помощью этого метода можно также определить число компонент связности графа.
Следует иметь в виду, что результат поиска в глубину зависит от выбора начальной вершины и порядка вершин в списках смежности.
|
|
|
|
Алгоритм 3.1.1 (поиск в глубину).
Вход: граф G = (V, E), представленный списками смежности вершин.
Выход: последовательность обхода вершин.
1. procedure
2. begin
3.
4. for do
5. if then
6. begin
7. ; father
8. end
9. else if and father then
10.
1 DFS – depth first search
11. end;
12. begin
13. ;
14. for do num ;
15. for do
16. if then
17. begin
18. father
19. end
20. end.
Алгоритм поиска в глубину в графе G начинается с некоторой начальной вершины (с этого момента вершина считается просмотренной). Далее алгоритм просматривает вершины графа G в определенном порядке. Для того чтобы зафиксировать этот порядок используется массив . При этом естественно считать, что , если начальная вершина, и , если вершина просматривается сразу после того, как просмотрена вершина u. Равенство означает, что вершина еще не просмотрена. Через father[u] обозначается та вершина x, из которой попали в вершину u. Ребро в этом случае называется древесным; T – множество древесных ребер. Все остальные ребра графа называются обратными, и их множество обозначается через B.
Пример 3.1.1. Результат поиска в глубину на графе и орграфе проиллюстрирован на рисунках 3.1.1 (a, б). При поиске помечаем вершины, присваивая им номера. Каждая новая вершина получает номер на единицу больший, чем текущая. Вершине присвоен номер 1. Номера остальных вершин, присвоенные им в процессе поиска, приведены на графах.
Подробнее рассмотрим обход в глубину на простом графе (рис. 3.1.1, а). В качестве начальной вершины взята вершина . Список смежности вершины . Отмечаем вершину и просматриваем вершины из ее списка смежности . В этом списке вершина неотмеченная, отмечаем ее и просматриваем список смежности вершины : , причем вершина – отмеченная. Поэтому отмечаем вершину . Далее , отмечаем вершину , список смежности которой , и из вершины идем в неотмеченную вершину . . Отмечаем вершину . В списке смежности неотмеченных вершин нет, поэтому возвращаемся в вершину и идем из нее в вершину . Обход графа в глубину закончен, так как неотмеченных вершин нет.