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

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 1: Строка 1:
{{В разработке}}
 
 
== Описание алгоритма ==
 
== Описание алгоритма ==
 
Приведенный ниже псевдокод алгоритма находит [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров цикл]] как в [[Ориентированный граф|ориентированном графе]], так и в неориентированном графе. Чтобы построить [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров путь]], нужно запустить функцию из вершины с нечетной степенью.
 
Приведенный ниже псевдокод алгоритма находит [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров цикл]] как в [[Ориентированный граф|ориентированном графе]], так и в неориентированном графе. Чтобы построить [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров путь]], нужно запустить функцию из вершины с нечетной степенью.
Строка 14: Строка 13:
 
         remove(w, u)
 
         remove(w, u)
 
       else:
 
       else:
 +
        stack.pop()
 
         print w
 
         print w
 
</font>
 
</font>
  
 
== Доказательство ==
 
== Доказательство ==
Заметим, что рано или поздно
+
Заметим, что рано или поздно алгоритм закончит свое выполнение, так как количество вершин, которое добавится в стек, не превышает количества ребер. А на каждой итерации цикла, в стек либо добавляется вершина, либо удаляется. Ясно, что в стеке всегда лежит какой-то путь и оператор ''print'' напечатает какой-то путь.
  
Рассмотрим последнее выполнение оператора ''print''.
+
Пусть <tex>P</tex> - это напечатанный после окончания работы алгоритма путь. Заметим, что вершина <tex>w</tex> напечатается, только в том случае, если все ребра, инцидентные с <tex>w</tex>, уже пройдены. Отсюда следует, что для любой вершины из <tex> P </tex> все инцидентные ей ребра содержатся в <tex> P </tex>. Поскольку эйлеров граф содержит не больше одной компоненты связности с более чем одной вершиной, то <tex> P </tex> содержит все ребра графа. А значит напечатанный путь эйлеров. <tex> \Box </tex>
 
 
Если мы запустим процедуру ''findPath'' из какой-нибудь вершины <tex> v_1 </tex>, то самой первой она и будет напечатана, так как у всех остальных вершин изначально четная степень, если мы в какую-нибудь из них войдем по одному ребру, то сможем выйти по другому. Если записать все вершины, в порядке входа в них, то получится циклический путь <tex> v_1 v_2 v_3 \ldots v_k</tex>. При выходе из функции вершины будут напечатаны в обратном порядке, относительно того, как они шли в циклическом пути <tex> v_k v_{k - 1} \ldots v_i</tex>. Возврат из рекурсии будет осуществляться до того момента, как мы либо совсем выйдем из рекурсии (что значит, что наш алгоритм напечатал циклический путь), либо из вершины <tex>v_i </tex> будут существовать еще ребра. Во втором случае, алгоритм опустится в рекурсию (и у вершины <tex> v_i </tex> степень станет нечетной, следовательно, как и в первом случае, из нее мы выйдем в первую очередь) и найдет какой-то эйлеров цикл, который содержит вершину <tex> v_i </tex> и состоит из некоторых ребер, которые мы еще не удаляли. После этого у нас будет напечатан <tex> v_k v_{k-1} \ldots v_i \ldots v_i </tex>. И так далее, проделывая такие операции, напечатается эйлеров цикл.
 
 
 
Почему напечатанный цикл будет эйлеровым? Во-первых, так как все компоненты связности, кроме, может быть, одной состоят из одной вершины, то если ''findPath'' запустится от вершины с ненулевой степенью, он просмотрит все вершины и все ребра из этой компоненты связности.  
 
Во-вторых, по каждому ребру алгоритм пройдет не более одного раза, потому что после просмотра этого ребра, оно сразу же удаляется из множества. <tex> \Box </tex>
 
  
 
== Время работы ==
 
== Время работы ==
Если реализовать удаление ребер за <tex>O(1)</tex>, то алгоритм будет работать за <tex>O(E)</tex>, так как каждое ребро будет просмотрено не более одного раза и запусков функции будет не больше, чем количество ребер.
+
Если реализовать удаление ребер за <tex>O(1)</tex>, то алгоритм будет работать за <tex>O(E)</tex>.
  
 
== См. также ==
 
== См. также ==

Версия 19:56, 4 ноября 2010

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

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

Псевдокод

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

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

Заметим, что рано или поздно алгоритм закончит свое выполнение, так как количество вершин, которое добавится в стек, не превышает количества ребер. А на каждой итерации цикла, в стек либо добавляется вершина, либо удаляется. Ясно, что в стеке всегда лежит какой-то путь и оператор print напечатает какой-то путь.

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

Время работы

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

См. также