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

Материал из Викиконспекты
Перейти к: навигация, поиск
(Сложность алгоритма)
(Псевдокод)
Строка 13: Строка 13:
  
 
== Псевдокод ==
 
== Псевдокод ==
 +
Функция <tex>findHamiltonianCycle</tex> получает на вход очередь вершин и находит гамильтонов цикл в графе.
 +
 
{| width = 100%
 
{| width = 100%
 
|-
 
|-
 
|  
 
|  
  <font color = "green">// g[][] - булевская матрица смежности</font>
+
   '''function''' <tex>\mathtt{findHamiltonianCycle}(queue):</tex>
   '''Queue''' queue                                          <font color = "green">// создаем очередь</font>
+
      '''for''' k = 0...n*(n - 1)
  '''for''' i = 0 '''to''' n - 1                                   
+
        '''if''' <tex>(queue.\mathtt{at}(0), queue.\mathtt{at}(1)) \notin E</tex>                 <font color = "green">// Проверяем существования ребра между первой и второй вершинами очереди</font>
    queue.pushBack(v[i])                               <font color = "green">// добавляем в очередь все вершины графа</font>
+
          <tex>i = 2</tex>                                              
  '''for''' k = 0 '''to''' n*(n - 1)                               <font color = "green">// пока не проделано нужное количество итераций</font>
+
          '''while''' <tex>(queue.\mathtt{at}(0), queue.\mathtt{at}(i)) \notin E</tex> '''or''' <tex>(queue.at(1), queue.at(i + 1)) \notin E</tex>
    '''if''' '''not''' g[queue.at(0), queue.at(1)]                 <font color = "green">// проверяем существования ребра между первой и второй вершинами очереди</font>
+
              <tex>i</tex>++                                        <font color = "green">// Ищем индекс удовлетворяющую условию вершины</font>
      i = 2                                             
+
           <tex>queue.\mathtt{swapSubQueue}(2, i)</tex>                        <font color = "green">// Разворачиваем часть перестановки от 2-й до найденной позиции включительно</font>
      '''while''' '''not''' g[queue.at(0), queue.at(i)]
+
        <tex>queue.\mathtt{pushBack}(queue.\mathtt{top}())</tex>
        '''or''' '''not''' g[queue.at(1), queue.at(i + 1)]          <font color = "green">// ищем индекс удовлетворяющую условию вершины</font>
+
        <tex>queue.\mathtt{pop}()</tex>
           i++                                           
 
      queue.swapSubQueue(2, i)                         <font color = "green">// разворачиваем часть перестановки от 2-й до найденной позиции включительно</font>
 
    queue.pushBack(queue.top())                         <font color = "green">// Добавляем первую вершину в конец очереди</font>
 
    queue.pop()                                         <font color = "green">// а из начала очереди удаляем</font>
 
 
 
 
|}
 
|}
  

Версия 20:30, 8 ноября 2015

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

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

Поступим следующим образом: заведем очередь и положим в нее все вершины нашего графа (не важно в каком порядке). Пусть [math] n = \left | V \right |[/math]. Тогда [math]n(n -1)[/math] раз будем делать следующую операцию:

  • Пусть [math] v_1 [/math] — это голова очереди, [math] v_2 [/math] — следующая за ней вершина и так далее. Если между первой и второй вершиной в очереди есть ребро в графе [math]G[/math], то перемещаем первую вершину в конец очереди и переходим к следующей итерации.
  • Если между первой и второй вершиной в очереди ребра нет, то найдем вершину [math]v_i[/math], где [math]i \gt 2[/math], такую что, ребра [math]v_1v_i, v_2v_{i+1} \in 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] пробегает все значения от [math]0[/math] до значения заданного неравенством). Теперь у нас появилось ребро между первой и второй вершинами в очереди (теперь вторая вершина, это та, которая была до разворота на [math]i[/math]-й позиции), а также, гарантированно существует ребро между [math]i[/math]-й и [math](i+1)[/math]-й вершинами очереди. После этого, так же как и в первом случае, оправляем первую вершину в конец очереди.

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

Псевдокод

Функция [math]findHamiltonianCycle[/math] получает на вход очередь вершин и находит гамильтонов цикл в графе.

 function [math]\mathtt{findHamiltonianCycle}(queue):[/math]
     for k = 0...n*(n - 1)
       if [math](queue.\mathtt{at}(0), queue.\mathtt{at}(1)) \notin E[/math]                  // Проверяем существования ребра между первой и второй вершинами очереди
         [math]i = 2[/math]                                             
         while [math](queue.\mathtt{at}(0), queue.\mathtt{at}(i)) \notin E[/math] or [math](queue.at(1), queue.at(i + 1)) \notin E[/math]
             [math]i[/math]++                                         // Ищем индекс удовлетворяющую условию вершины
         [math]queue.\mathtt{swapSubQueue}(2, i)[/math]                        // Разворачиваем часть перестановки от 2-й до найденной позиции включительно
       [math]queue.\mathtt{pushBack}(queue.\mathtt{top}())[/math]
       [math]queue.\mathtt{pop}()[/math]

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

Лемма:
Каждый раз, когда нам надо искать вершину [math]v_i[/math], где [math]i \gt 2[/math], такую что [math]v_1v_i, v_2v_{i+1} \in E[/math], такая вершина действительно существует.
Доказательство:
[math]\triangleright[/math]
Рассмотрим множество [math]S = \{i\mid v_1v_i \in E\}[/math], состоящее из индексов вершин, смежных с [math]v_1[/math], и множество [math]T = \{i+1 \mid v_2v_{i+1} \in E\}[/math], индексов вершин смежных с [math]v_2[/math]. Заметим, что [math]S \subset \{3, 4, \ldots, n\}[/math], а [math]T \subset \{2, 3, \ldots, n - 1\}[/math], тогда [math]S\cup T\subset \{2, 3, \ldots, n\} [/math], а значит [math]\left\vert S\cup T\right\vert \leqslant n-1[/math], в то же время [math]\left\vert S \right\vert + \left\vert T \right\vert = \operatorname{deg} v_1 + \operatorname{deg} v_2 \geqslant n[/math] (по условию теоремы Оре или теоремы Дирака). Из этого следует, что [math]S\cap T\ne \varnothing[/math], а это и значит, что искомая вершина существует.
[math]\triangleleft[/math]
Лемма:
После [math]n(n - 1)[/math] итераций между каждой парой соседних вершин очереди существует ребро.
Доказательство:
[math]\triangleright[/math]
Достаточно заметить, что каждую итерацию алгоритма, мы, в случае отсутствия ребра, между [math]v_1[/math] и [math]v_{2}[/math] увеличиваем количество пар соседних в очереди вершин, между которыми есть ребро, как минимум на [math]1[/math] (это прямое следствие условия поиска нужной вершины, в случае отсутствия ребра), для поиска такой пары требуется не более [math]n[/math] итераций. Таких пар изначально не более [math]n[/math], откуда следует, что после [math]n[/math] итераций, второе условие будет выполнено.
[math]\triangleleft[/math]
Теорема:
Алгоритм находит гамильтонов цикл.
Доказательство:
[math]\triangleright[/math]
Из предыдущих лемм следует корректность алгоритма.
[math]\triangleleft[/math]

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

Поиск вершины, удовлетворяющей заданному условию работает за [math]O(n)[/math], а таких поисков будет осуществлено не более чем [math]n[/math]. Оставшиеся [math]n(n - 2)[/math] итерации выполняются за [math]O(1)[/math]. Тогда алгоритм выполняется за [math]O(n^2)[/math].

См.также

Источники информации