Алгоритм построения Эйлерова цикла — различия между версиями
м |
|||
Строка 1: | Строка 1: | ||
− | == Описание алгоритма == | + | === Описание алгоритма === |
Алгоритм находит [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров цикл]] как в [[Ориентированный граф|ориентированном]], так и в [[Основные определения теории графов#Неориентированные графы|неориентированном графе]]. Перед запуском алгоритма необходимо [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|проверить граф на эйлеровость]]. Чтобы построить [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров путь]], нужно запустить алгоритм из вершины с нечетной степенью.<br> | Алгоритм находит [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров цикл]] как в [[Ориентированный граф|ориентированном]], так и в [[Основные определения теории графов#Неориентированные графы|неориентированном графе]]. Перед запуском алгоритма необходимо [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|проверить граф на эйлеровость]]. Чтобы построить [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров путь]], нужно запустить алгоритм из вершины с нечетной степенью.<br> | ||
Алгоритм напоминает поиск в глубину. Главное отличие состоит в том, что пройденными помечаются не вершины, а ребра графа. Начиная со стартовой вершины <tex>v</tex> строим путь, добавляя на каждом шаге не пройденное еще ребро, смежное с текущей вершиной. Вершины пути накапливаются в [[Стек | стеке]] <tex>S</tex>. Когда наступает такой момент, что для текущей вершины <tex>w</tex> все инцидентные ей ребра уже пройдены, записываем вершины из <tex>S</tex> в ответ, пока не встретим вершину, которой инцидентны не пройденные еще ребра. Далее продолжаем обход по не посещенным ребрам. | Алгоритм напоминает поиск в глубину. Главное отличие состоит в том, что пройденными помечаются не вершины, а ребра графа. Начиная со стартовой вершины <tex>v</tex> строим путь, добавляя на каждом шаге не пройденное еще ребро, смежное с текущей вершиной. Вершины пути накапливаются в [[Стек | стеке]] <tex>S</tex>. Когда наступает такой момент, что для текущей вершины <tex>w</tex> все инцидентные ей ребра уже пройдены, записываем вершины из <tex>S</tex> в ответ, пока не встретим вершину, которой инцидентны не пройденные еще ребра. Далее продолжаем обход по не посещенным ребрам. | ||
− | == Псевдокод == | + | === Псевдокод === |
<font size=2> | <font size=2> | ||
'''Код проверки графа на эйлеровость:''' | '''Код проверки графа на эйлеровость:''' | ||
Строка 37: | Строка 37: | ||
</font> | </font> | ||
− | == Доказательство корректности == | + | === Доказательство корректности === |
− | + | {{Теорема | |
− | Так как после прохода по ребру оно удаляется, то пройти по нему дважды алгоритм не может. <br> | + | |id=proof1 |
− | + | |statement=Данный алгоритм находит корректный эйлеров путь. | |
+ | |proof= | ||
+ | Данный алгоритм проходит по каждому ребру, причем ровно один раз. Допустим, что в момент окончания работы алгоритма имеются еще не пройденные ребра. Поскольку граф связен, должно существовать хотя бы одно непройденное ребро, инцидентное посещенной вершине. Но тогда эта вершина не могла быть удалена из <tex>S</tex>, и <tex>S</tex> не мог стать пустым. Так как после прохода по ребру оно удаляется, то пройти по нему дважды алгоритм не может.<br> | ||
+ | Напечатанный путь <tex>P</tex> {{---}} корректный маршрут в графе, в котором каждые два ребра подряд инцидентны одной вершине. Будем говорить, что ребро <tex>(w,u)</tex> представлено в <tex>S</tex> или <tex>P</tex>, если в какой-то момент работы алгоритма вершины <tex>w</tex> и <tex>u</tex> находятся рядом. Каждое ребро графа представлено в <tex>S</tex>. Рассмотрим случай, когда из <tex>S</tex> в <tex>P</tex> перемещена вершина <tex>w</tex>, а следующей в <tex>S</tex> лежит <tex>u</tex>. Возможны 2 варианта: | ||
#На следующем шаге <tex>u</tex> перемещена в <tex>P</tex>. Тогда <tex>(w,u)</tex> представлено в <tex>P</tex>. | #На следующем шаге <tex>u</tex> перемещена в <tex>P</tex>. Тогда <tex>(w,u)</tex> представлено в <tex>P</tex>. | ||
#Сначала будет пройдена некоторая последовательность ребер, начинающаяся в вершине <tex>u</tex>. Ввиду четности степеней эта последовательность может закончиться только в вершине <tex>u</tex>, а значит она следующей попадет в <tex>P</tex> и <tex>(w,u)</tex> будет представлено в <tex>P</tex>. | #Сначала будет пройдена некоторая последовательность ребер, начинающаяся в вершине <tex>u</tex>. Ввиду четности степеней эта последовательность может закончиться только в вершине <tex>u</tex>, а значит она следующей попадет в <tex>P</tex> и <tex>(w,u)</tex> будет представлено в <tex>P</tex>. | ||
− | + | Так как алгоритм проходит по каждому ребру, причем ровно 1 раз, а путь <tex>P</tex> корректен, следует, что <tex>P</tex> {{---}} искомый эйлеров путь. | |
− | + | }} | |
− | + | === Рекурсивная реализация === | |
− | == Рекурсивная реализация == | ||
<font size=2> | <font size=2> | ||
'''function''' findEulerPath(<tex>v</tex> : Vertex): | '''function''' findEulerPath(<tex>v</tex> : Vertex): | ||
Строка 54: | Строка 56: | ||
print(<tex>v</tex>) | print(<tex>v</tex>) | ||
</font> | </font> | ||
− | + | === Время работы === | |
− | == Время работы == | ||
Если реализовать поиск ребер инцидентных вершине и удаление ребер за <tex>O(1)</tex>, то алгоритм будет работать за <tex>O(E)</tex>.<br> | Если реализовать поиск ребер инцидентных вершине и удаление ребер за <tex>O(1)</tex>, то алгоритм будет работать за <tex>O(E)</tex>.<br> | ||
Чтобы реализовать поиск за <tex>O(1)</tex>, для хранения графа следует использовать списки смежных вершин; для удаления достаточно добавить всем ребрам свойство <tex>\mathtt{deleted}</tex> бинарного типа. | Чтобы реализовать поиск за <tex>O(1)</tex>, для хранения графа следует использовать списки смежных вершин; для удаления достаточно добавить всем ребрам свойство <tex>\mathtt{deleted}</tex> бинарного типа. |
Версия 10:45, 12 января 2015
Содержание
Описание алгоритма
Алгоритм находит Эйлеров цикл как в ориентированном, так и в неориентированном графе. Перед запуском алгоритма необходимо проверить граф на эйлеровость. Чтобы построить Эйлеров путь, нужно запустить алгоритм из вершины с нечетной степенью.
Алгоритм напоминает поиск в глубину. Главное отличие состоит в том, что пройденными помечаются не вершины, а ребра графа. Начиная со стартовой вершины строим путь, добавляя на каждом шаге не пройденное еще ребро, смежное с текущей вершиной. Вершины пути накапливаются в стеке . Когда наступает такой момент, что для текущей вершины все инцидентные ей ребра уже пройдены, записываем вершины из в ответ, пока не встретим вершину, которой инцидентны не пройденные еще ребра. Далее продолжаем обход по не посещенным ребрам.
Псевдокод
Код проверки графа на эйлеровость:
boolean checkForEulerPath(): int numberOfOdd = 0 forin if mod 2 == 1 numberOfOdd = numberOfOdd + 1 if numberOfOdd > 2 // если количество вершин с нечетной степенью больше двух, то граф не является эйлеровым return false boolean vis[sizeOf ] // инициализировать массив значениями false for in if > 0 dfs( , vis) break for in if > 0 and not vis[ ] // если количество компонент связности, содержащие ребра, больше одной, return false // то граф не является эйлеровым return true // граф является эйлеровым
Код построения эйлерова пути:
function findEulerPath(: Vertex): // если граф является полуэйлеровым, то алгоритм следует запускать из вершины нечетной степени Stack S S.push( ) while not S.isEmpty() = S.top() if exists in S.push( ) remove else S.pop() print( )
Доказательство корректности
Теорема: |
Данный алгоритм находит корректный эйлеров путь. |
Доказательство: |
Данный алгоритм проходит по каждому ребру, причем ровно один раз. Допустим, что в момент окончания работы алгоритма имеются еще не пройденные ребра. Поскольку граф связен, должно существовать хотя бы одно непройденное ребро, инцидентное посещенной вершине. Но тогда эта вершина не могла быть удалена из
|
Рекурсивная реализация
function findEulerPath(: Vertex): for in remove findEulerPath( ) print( )
Время работы
Если реализовать поиск ребер инцидентных вершине и удаление ребер за
Чтобы реализовать поиск за , для хранения графа следует использовать списки смежных вершин; для удаления достаточно добавить всем ребрам свойство бинарного типа.