<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.162.6.8&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=178.162.6.8&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/178.162.6.8"/>
		<updated>2026-05-24T01:06:51Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD%D0%B8%D1%8F_%D0%AD%D0%B9%D0%BB%D0%B5%D1%80%D0%BE%D0%B2%D0%B0_%D1%86%D0%B8%D0%BA%D0%BB%D0%B0&amp;diff=50027</id>
		<title>Алгоритм построения Эйлерова цикла</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%BF%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD%D0%B8%D1%8F_%D0%AD%D0%B9%D0%BB%D0%B5%D1%80%D0%BE%D0%B2%D0%B0_%D1%86%D0%B8%D0%BA%D0%BB%D0%B0&amp;diff=50027"/>
				<updated>2015-11-22T16:59:24Z</updated>
		
		<summary type="html">&lt;p&gt;178.162.6.8: слово ширина&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Алгоритм ==&lt;br /&gt;
=== Описание алгоритма ===&lt;br /&gt;
Алгоритм находит [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров цикл]] как в [[Ориентированный граф|ориентированном]], так и в [[Основные определения теории графов#Неориентированные графы|неориентированном графе]]. Перед запуском алгоритма необходимо [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|проверить граф на эйлеровость]]. Чтобы построить [[Эйлеров цикл, Эйлеров путь, Эйлеровы графы, Эйлеровость орграфов|Эйлеров путь]], нужно запустить алгоритм из вершины с нечетной степенью.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм напоминает поиск в ширину. Главное отличие состоит в том, что пройденными помечаются не вершины, а ребра графа. Начиная со стартовой вершины &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; строим путь, добавляя на каждом шаге не пройденное еще ребро, смежное с текущей вершиной. Вершины пути накапливаются в [[Стек | стеке]] &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Когда наступает такой момент, что для текущей вершины &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; все инцидентные ей ребра уже пройдены, записываем вершины из &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; в ответ, пока не встретим вершину, которой инцидентны не пройденные еще ребра. Далее продолжаем обход по не посещенным ребрам.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
&amp;lt;font size=2&amp;gt;&lt;br /&gt;
'''Код проверки графа на эйлеровость:'''&lt;br /&gt;
 '''boolean''' checkForEulerPath():&lt;br /&gt;
    '''int''' numberOfOdd = 0&lt;br /&gt;
    '''for''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\in&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;&lt;br /&gt;
        '''if''' &amp;lt;tex&amp;gt;\operatorname{deg} v&amp;lt;/tex&amp;gt; '''mod''' 2 == 1&lt;br /&gt;
            numberOfOdd = numberOfOdd + 1&lt;br /&gt;
    '''if''' numberOfOdd &amp;gt; 2   &amp;lt;font color=darkgreen&amp;gt;// если количество вершин с нечетной степенью больше двух, то граф не является эйлеровым&amp;lt;/font&amp;gt;&lt;br /&gt;
        '''return''' ''false''&lt;br /&gt;
    '''boolean''' vis[&amp;lt;tex&amp;gt;|V|&amp;lt;/tex&amp;gt;]   &amp;lt;font color=darkgreen&amp;gt;// инициализировать массив значениями ''false''&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\in&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;&lt;br /&gt;
        '''if''' &amp;lt;tex&amp;gt;\operatorname{deg} v&amp;lt;/tex&amp;gt; &amp;gt; 0&lt;br /&gt;
            dfs(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, vis)&lt;br /&gt;
            break&lt;br /&gt;
    '''for''' &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\in&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;V&amp;lt;/tex&amp;gt;&lt;br /&gt;
        '''if''' &amp;lt;tex&amp;gt;\operatorname{deg} v&amp;lt;/tex&amp;gt; &amp;gt; 0 '''and''' '''not''' vis[&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;]   &amp;lt;font color=darkgreen&amp;gt;// если количество компонент связности, содержащие ребра, больше одной,&amp;lt;/font&amp;gt;&lt;br /&gt;
            '''return''' ''false''             &amp;lt;font color=darkgreen&amp;gt; // то граф не является эйлеровым&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''return''' ''true''   &amp;lt;font color=darkgreen&amp;gt;// граф является эйлеровым&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Код построения эйлерова пути:'''&lt;br /&gt;
 '''function''' findEulerPath(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; : Vertex):  &amp;lt;font color=darkgreen&amp;gt; // если граф является полуэйлеровым, то алгоритм следует запускать из вершины нечетной степени &amp;lt;/font&amp;gt;&lt;br /&gt;
    Stack S&lt;br /&gt;
    S.push(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    '''while not''' S.isEmpty()&lt;br /&gt;
        &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; = S.top()&lt;br /&gt;
        '''if''' &amp;lt;tex&amp;gt;(w, u)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\in&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;&lt;br /&gt;
            S.push(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;)&lt;br /&gt;
            remove &amp;lt;tex&amp;gt;(w, u)&amp;lt;/tex&amp;gt;&lt;br /&gt;
        '''else''' &lt;br /&gt;
            S.pop()&lt;br /&gt;
            print(&amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;)&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Доказательство корректности ===&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|id=proof1&lt;br /&gt;
|statement=Данный алгоритм находит корректный эйлеров путь.&lt;br /&gt;
|proof=&lt;br /&gt;
{{TODO | t = Довести до ума}}&amp;lt;br&amp;gt;&lt;br /&gt;
Данный алгоритм проходит по каждому ребру, причем ровно один раз. Допустим, что в момент окончания работы алгоритма имеются еще не пройденные ребра. Поскольку граф связен, должно существовать хотя бы одно непройденное ребро, инцидентное посещенной вершине. Но тогда эта вершина не могла быть удалена из &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, и &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не мог стать пустым. Так как после прохода по ребру оно удаляется, то пройти по нему дважды алгоритм не может.&amp;lt;br&amp;gt;&lt;br /&gt;
Вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, с которой начат обход графа, будет последней помещена в путь &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt;. Так как изначально стек пуст, и вершина &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; входит в стек первой, то после прохода по инцидентным ребрам, алгоритм возвращается к данной вершине, выводит ее и опустошает стек, затем выполнение программы завершается.&amp;lt;br&amp;gt;&lt;br /&gt;
Напечатанный путь &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; {{---}} корректный маршрут в графе, в котором каждые две соседние вершины &amp;lt;tex&amp;gt;u_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;u_{i+1}&amp;lt;/tex&amp;gt; будут образовывать ребро &amp;lt;tex&amp;gt;(u_i, u_{i+1})&amp;lt;/tex&amp;gt;, принадлежащее &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;. Будем говорить, что ребро &amp;lt;tex&amp;gt;(w,u)&amp;lt;/tex&amp;gt; представлено в &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt;, если в какой-то момент работы алгоритма вершины &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; находятся рядом. Каждое ребро графа представлено в &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Рассмотрим случай, когда из &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; перемещена вершина &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, а следующей в &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; лежит &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;. Возможны 2 варианта:&lt;br /&gt;
#На следующем шаге &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt; перемещена в &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;(w,u)&amp;lt;/tex&amp;gt; представлено в &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt;.&lt;br /&gt;
#Сначала будет пройдена некоторая последовательность ребер, начинающаяся в вершине &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;, и проходящая по ребру &amp;lt;tex&amp;gt;(w, u_1)&amp;lt;/tex&amp;gt;. Докажем, что данный проход &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;{u_1, u_2, ..., u_k}&amp;lt;/tex&amp;gt; закончится в вершине &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;: ребро &amp;lt;tex&amp;gt;(u_{k-1}, u_k)&amp;lt;/tex&amp;gt; не может быть инцидентно вершинам &amp;lt;tex&amp;gt;u_1, \dots , u_{k-2}&amp;lt;/tex&amp;gt;. Иначе степень вершины &amp;lt;tex&amp;gt;u_k&amp;lt;/tex&amp;gt; будет нечетной. Предположим, что &amp;lt;tex&amp;gt;(u_{k-1}, u_k)&amp;lt;/tex&amp;gt; инцидентно вершине, пройденной при обходе графа из вершины &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;. Но это неверно, так как тогда бы данные вершины пройдены ранее. Из этого следует, что мы закончим обход в вершине &amp;lt;tex&amp;gt;w&amp;lt;/tex&amp;gt;. Следовательно, данная вершина первой поместится в &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; вслед за &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;, и ребро &amp;lt;tex&amp;gt;(w, u)&amp;lt;/tex&amp;gt; будет представлено в &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Из этого следует, что &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; {{---}} искомый эйлеров путь.&lt;br /&gt;
}}&lt;br /&gt;
=== Рекурсивная реализация ===&lt;br /&gt;
&amp;lt;font size=2&amp;gt;&lt;br /&gt;
 '''function''' findEulerPath(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; : Vertex):&lt;br /&gt;
    '''for''' &amp;lt;tex&amp;gt;(v,u)&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\in&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;E&amp;lt;/tex&amp;gt;&lt;br /&gt;
        remove &amp;lt;tex&amp;gt;(v, u)&amp;lt;/tex&amp;gt;&lt;br /&gt;
        findEulerPath(&amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt;)&lt;br /&gt;
    print(&amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;)&lt;br /&gt;
&amp;lt;/font&amp;gt;&lt;br /&gt;
=== Время работы ===&lt;br /&gt;
Если реализовать поиск ребер инцидентных вершине и удаление ребер за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, то алгоритм будет работать за &amp;lt;tex&amp;gt;O(E)&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
Чтобы реализовать поиск за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;, для хранения графа следует использовать списки смежных вершин; для удаления достаточно добавить всем ребрам свойство &amp;lt;tex&amp;gt;\mathtt{deleted}&amp;lt;/tex&amp;gt; бинарного типа.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Гамильтоновы графы]]&lt;br /&gt;
* [[Покрытие ребер графа путями]]&lt;br /&gt;
* [[Произвольно вычерчиваемые из заданной вершины графы]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/Эйлеров_цикл Википедия {{---}} Эйлеров цикл]&lt;br /&gt;
* [http://e-maxx.ru/algo/euler_path  Статья про нахождение Эйлерова пути с реализацией на С++ на сайте e-maxx.ru]&lt;br /&gt;
* [http://ивтб.рф/exams/саод/36.htm  Статья про нахождение Эйлерова пути с реализацией на Pascal на сайте ивтб.рф]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Обходы графов]]&lt;/div&gt;</summary>
		<author><name>178.162.6.8</name></author>	</entry>

	</feed>