Алгоритм построения Эйлерова цикла — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Псевдокод)
(Доказательство)
Строка 18: Строка 18:
  
 
== Доказательство ==
 
== Доказательство ==
Заметим, что рано или поздно алгоритм закончит свое выполнение, так как количество вершин, которое добавится в стек, не превышает количества ребер. А на каждой итерации цикла, в стек либо добавляется вершина, либо удаляется. Ясно, что в стеке всегда лежит какой-то путь и оператор ''print'' напечатает какой-то путь.
+
Пусть <tex>P</tex> - напечатанный путь. Заметим, что первой в <tex>S</tex> помещается вершина <tex>v</tex>, и она будет последней перемещена из <tex>S</tex> в <tex>P</tex>. Следовательно, она будет последней вершиной в <tex>P</tex>. Далее, как было отмечено выше, первый раз, когда обнаружится, что все инцидентные активной вершине ребра пройдены, активной будет стартовая вершина <tex>v</tex>. Значит, эта вершина будет первой перемещена из <tex>S</tex> в <tex>P</tex>. Итак, по окончании работы алгоритма в начале и в конце последовательности вершин, содержащейся в <tex>P</tex>, находится вершина <tex>v</tex>. Иначе говоря, если эта последовательность представляет маршрут, то этот маршрут замкнут.<br>
 
+
Покажем, что маршрут замкнут.<br>
Пусть <tex>P</tex> - это напечатанный после окончания работы алгоритма путь. Заметим, что вершина <tex>w</tex> напечатается только в том случае, если все ребра, инцидентные <tex>w</tex>, уже пройдены. Отсюда следует, что для любой вершины из <tex> P </tex> все инцидентные ей ребра содержатся в <tex> P </tex>. В ходе алгоритма для каждой вершины в стек попадают все смежные с ней вершины, а так как алгоритм работает до опустошения стека, все они в итоге попадут в <tex> P </tex>. Поскольку эйлеров граф содержит не больше одной компоненты связности с более чем одной вершиной, то <tex> P </tex> содержит все ребра графа. А значит напечатанный путь эйлеров. <tex> \Box </tex>
+
Отметим, что в конечном итоге каждое ребро будет пройдено. Действительно, допустим, что в момент окончания работы алгоритма имеются еще не пройденные ребра. Поскольку граф связен, должно существовать хотя бы одно непройденное ребро, инцидентное посещенной вершине. Но тогда эта вершина не могла быть удалена из <tex>S</tex>, и <tex>S</tex> не мог стать пустым.
 +
<tex> \Box </tex>
  
 
== Рекурсивная реализация ==  
 
== Рекурсивная реализация ==  

Версия 01:17, 24 февраля 2012

Описание алгоритма

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

Псевдокод

 findPath(v):
   S.clear()
   S.add(v)
   while not stack.isEmpty():
     w := S.top()
     if E contains (w, u):
       S.add(u)
       remove(w, u)
     else:
       S.pop()
       print w

Доказательство

Пусть [math]P[/math] - напечатанный путь. Заметим, что первой в [math]S[/math] помещается вершина [math]v[/math], и она будет последней перемещена из [math]S[/math] в [math]P[/math]. Следовательно, она будет последней вершиной в [math]P[/math]. Далее, как было отмечено выше, первый раз, когда обнаружится, что все инцидентные активной вершине ребра пройдены, активной будет стартовая вершина [math]v[/math]. Значит, эта вершина будет первой перемещена из [math]S[/math] в [math]P[/math]. Итак, по окончании работы алгоритма в начале и в конце последовательности вершин, содержащейся в [math]P[/math], находится вершина [math]v[/math]. Иначе говоря, если эта последовательность представляет маршрут, то этот маршрут замкнут.
Покажем, что маршрут замкнут.
Отметим, что в конечном итоге каждое ребро будет пройдено. Действительно, допустим, что в момент окончания работы алгоритма имеются еще не пройденные ребра. Поскольку граф связен, должно существовать хотя бы одно непройденное ребро, инцидентное посещенной вершине. Но тогда эта вершина не могла быть удалена из [math]S[/math], и [math]S[/math] не мог стать пустым. [math] \Box [/math]

Рекурсивная реализация

 findPath(v):
   for (v, u) from E
     remove (v, u)
     findPath(u)
   print v

Время работы

Если реализовать удаление ребер за [math]O(1)[/math], то алгоритм будет работать за [math]O(E)[/math].

См. также