Алгоритм нахождения Гамильтонова цикла в условиях теорем Дирака и Оре — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Описание алгоритма)
(Описание алгоритма)
Строка 1: Строка 1:
 
__TOC__
 
__TOC__
 
== Описание алгоритма ==
 
== Описание алгоритма ==
Алгоритм находит [[Гамильтоновы графы|гамильтонов цикл]] в [[Основные определения теории графов#Неориентированные графы|неориентированном графе]] <tex> \mathbb{G} = (\mathbb{V}, \mathbb{E}) </tex>, если выполняются условия [[Теорема Оре|теоремы Оре]] или выполнена [[теорема Дирака]]. Рассмотрим перестановку вершин <tex> \mathrm{v}_1 \mathrm{v}_2 ... \mathrm{v}_n</tex>, где <tex>n = | \mathbb{V} |</tex>. Если между каждой парой соседних вершин в перестановке существует ребро, то мы получили [[Гамильтоновы графы|гамильтонов цикл]]. В противном случае, начиная с пары <tex> \mathrm{v}_1 \mathrm{v}_2 </tex>,  начнем последовательно рассматривать пары соседних вершин <tex> \mathrm{v}_i \mathrm{v}_{i+1} </tex>, пока <tex>i \ge n</tex> (когда <tex>i = n</tex>, за <tex>\mathrm{v}_{i+1}</tex> считаем <tex>\mathrm{v}_{1}</tex>).
+
Пусть у нас есть граф <tex>\mathbb{G} = \left \langle \mathbb{V, E} \right \rangle</tex>, удовлетворяющий условию [[Теорема Дирака|теоремы Оре]] или [[Теорема Дирака|теоремы Дирака]], и требуется найти в нем гамильтонов цикл. Поступим следующим образом: заведем очередь и положим в нее все вершины нашего графа(не важно в каком порядке). Теперь <tex>n = \left | \mathbb{V}\right |</tex> раз будем делать следующую операцию:
  
* Если между ними есть ребро, то переходим к следующей паре вершин <tex> \mathrm{v}_{i+1} \mathrm{v}_{i+2}</tex>.  
+
* Если между первой (здесь и далее первая вершина - вершина в голове очереди) и второй вершиной в очереди есть ребро в графе <tex>\mathbb{G}</tex>, то перемещаем первую вершину в конец очереди и переходим к следующей итерации.
* Если же ребра нет, то найдем такую вершину <tex>\mathrm{v}_j</tex> (то, что она всегда существует, будет показано ниже), что <tex> \mathrm{v}_j \in{\mathbb{V}} \setminus \{ \mathrm{v}_i, \mathrm{v}_{i+1} \} </tex>, и существуют ребра <tex> \mathrm{v}_i \mathrm{v}_j</tex> и <tex> \mathrm{v}_{i+1} \mathrm{v}_{j+1} </tex> (Если <tex> j = n</tex> , то за <tex>\mathrm{v}_{j+1}</tex> считаем <tex>\mathrm{v}_{1}</tex>).
+
* Если между первой и второй вершиной в очереди ребра нет, то найдем вершину <tex>v_i</tex>, такую что, ребра <tex>v_1v_i, v_2v_{i+1} \in \mathbb{E}</tex> (так как у нас для графа выполнена либо [[Теорема Оре|теорема Оре]], либо [[Теорема Дирака|теорема Дирака]], то такая вершина обязательно найдется; чуть позже мы это докажем явно). После чего поменяем в очереди местами вершины <tex>v_2</tex> и <tex>v_i</tex>, <tex>v_3</tex> и <tex>v_{i-1}</tex>, <tex>v_{2+j} </tex> и <tex>v_{i-j}</tex>, и так далее, пока <tex>2 + j < i - j</tex> (то есть <tex>j</tex> пробегает все значения от 0 до значения заданного неравенством). Теперь у нас появилось ребро между первой и второй вершинами в очереди (теперь вторая вершина, это та, которая была до разворота на <tex>i</tex>-й позиции), а так же, гарантированно существует ребро между <tex>i</tex>-й и <tex>(i+1)</tex>-й вершинами очереди. После этого, так же как и в первом случае, оправляем первую вершину в конец очереди.
** Если <tex>i < j </tex> то перевернем часть перестановки от <tex> i+1 </tex> до <tex> j </tex> (включительно).
+
 
** Если <tex> i > j </tex> обменяем в перестановке элементы на позициях <tex> (i + 1 + k)\ \operatorname{mod}\ n </tex> и <tex> (j - k +n)\ \operatorname{mod}\ n </tex>, где <tex>k = \overline{0, (j + n - i)\ \operatorname{div}\ 2}</tex>, то есть считаем <tex>\mathrm{v}_{i}...\mathrm{v}_{j}</tex> равной <tex>\mathrm{v}_{i}...\mathrm{v}_{n}\mathrm{v}_{1}...\mathrm{v}_{j}</tex>. Например, если <tex>n = 10, i = 8, j = 1</tex>, то <tex>\mathrm{v}_9 </tex> и <tex>\mathrm{v}_1</tex> поменяются местами, а <tex>\mathrm{v}_{10}</tex> останется на месте.
+
Таким образом после <tex>n</tex> итераций, мы получаем последовательность (вершины лежащие в очереди), где любые 2 соседние вершины соединены ребром, все вершины графа находятся в этой последовательности, и более того, каждая ровно один раз, а так же существует ребро между последней и первой вершинами очереди, а это и значит, что мы решили поставленную задачу.
  
 
== Псевдокод ==
 
== Псевдокод ==

Версия 16:02, 6 декабря 2013

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

Пусть у нас есть граф [math]\mathbb{G} = \left \langle \mathbb{V, E} \right \rangle[/math], удовлетворяющий условию теоремы Оре или теоремы Дирака, и требуется найти в нем гамильтонов цикл. Поступим следующим образом: заведем очередь и положим в нее все вершины нашего графа(не важно в каком порядке). Теперь [math]n = \left | \mathbb{V}\right |[/math] раз будем делать следующую операцию:

  • Если между первой (здесь и далее первая вершина - вершина в голове очереди) и второй вершиной в очереди есть ребро в графе [math]\mathbb{G}[/math], то перемещаем первую вершину в конец очереди и переходим к следующей итерации.
  • Если между первой и второй вершиной в очереди ребра нет, то найдем вершину [math]v_i[/math], такую что, ребра [math]v_1v_i, v_2v_{i+1} \in \mathbb{E}[/math] (так как у нас для графа выполнена либо теорема Оре, либо теорема Дирака, то такая вершина обязательно найдется; чуть позже мы это докажем явно). После чего поменяем в очереди местами вершины [math]v_2[/math] и [math]v_i[/math], [math]v_3[/math] и [math]v_{i-1}[/math], [math]v_{2+j} [/math] и [math]v_{i-j}[/math], и так далее, пока [math]2 + j \lt i - j[/math] (то есть [math]j[/math] пробегает все значения от 0 до значения заданного неравенством). Теперь у нас появилось ребро между первой и второй вершинами в очереди (теперь вторая вершина, это та, которая была до разворота на [math]i[/math]-й позиции), а так же, гарантированно существует ребро между [math]i[/math]-й и [math](i+1)[/math]-й вершинами очереди. После этого, так же как и в первом случае, оправляем первую вершину в конец очереди.

Таким образом после [math]n[/math] итераций, мы получаем последовательность (вершины лежащие в очереди), где любые 2 соседние вершины соединены ребром, все вершины графа находятся в этой последовательности, и более того, каждая ровно один раз, а так же существует ребро между последней и первой вершинами очереди, а это и значит, что мы решили поставленную задачу.

Псевдокод

 for i = 1 to n                           // перебираем все вершины перестановки [math]P[/math]
   if [math] v_i v_{i+1} \notin \mathbb{E} [/math]                         // если нет ребра между [math]v_i v_{i+1} [/math]
     for [math]v_j \in \mathbb{V} \setminus \{v_i, v_{i + 1}\}[/math]              // перебираем все остальные вершины 
       if [math]v_i v_j \in \mathbb{E}\[/math] && [math] v_{i+1} v_{j+1} \in \mathbb{E}[/math]      // если есть ребра [math]v_i v_j,\ v_{i+1} v_{j+1} [/math]
         reverse_subsequence([math]P, i+1, j[/math])  // разворачиваем часть перестановки [math]P[/math] от i+1 позиции до j
         break                           // переходим к следующей итерации внешнего for                       
       

Доказательство алгоритма

На [math]k[/math]-ой итерации внешнего цикла рассматриваются вершины [math]\mathrm{v}_k \mathrm{v}_{k+1}[/math]. Возможно 2 случая:

  • между ними есть ребро, и тогда делать ничего не надо;
  • между ними ребра нет, и тогда надо найти такую вершину [math]\mathrm{v}_j[/math], что [math]\mathrm{v}_k \mathrm{v}_j, \mathrm{v}_{k+1} \mathrm{v}_{j+1} \in \mathbb{E}[/math];

Покажем, что такая вершина обязательно найдется. Пусть [math]S= \{ i| \mathrm{e}_i = \mathrm{v}_k \mathrm{v}_i \in \mathbb{E}\} \subset \{1, 2, ...,n\} \setminus \{k,k+1\} [/math] и [math]T = \{ i| f_i=\mathrm{v}_k \mathrm{v}_{i+1} \in \mathbb{E} \} \subset \{1, 2, ...,n-1\} \setminus \{k\} [/math]. Тогда [math]S \cup T \subset \{1,2,...,n\} \setminus \{k\} [/math], откуда [math]|S \cup T |\lt n[/math]. Но [math]|S|+|T| = \operatorname{deg}\ v_1 + \operatorname{deg}\ v_2 \ge n[/math] по условию теоремы Оре или теоремы Дирака, в зависимости от наших начальных условий. А значит [math]S \cap T \ne \varnothing[/math], следовательно искомая вершина обязательно найдется. Теперь заметим, что после [math]k[/math]-ой итерации внешнего цикла между всеми парами вершин [math]\mathrm{v}_{i}, \mathrm{v}_{i+1}[/math], где [math]i \le k[/math] существует ребро, а значит после [math]n[/math] итераций мы найдем цикл.

Сложность алгоритма

Алгоритм работает за [math]O(n^2)[/math]. Действительно, количество итераций внешнего цикла [math]\mathrm{for}[/math] всегда равно [math]n[/math]. Во внутреннем цикле в худшем случае будет выполнено [math]n - 2[/math] итерации, получаем время работы [math]O(n^2)[/math].

См.также