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

Материал из Викиконспекты
Перейти к: навигация, поиск
(Псевдокод)
м (Псевдокод)
Строка 22: Строка 22:
 
       '''for''' <tex> v \in V</tex>:                                          <font color = "green">// Добавляем все вершины графа в очередь</font>
 
       '''for''' <tex> v \in V</tex>:                                          <font color = "green">// Добавляем все вершины графа в очередь</font>
 
         queue.pushBack(<tex>v</tex>)
 
         queue.pushBack(<tex>v</tex>)
       '''for''' k = 0...n*(n - 1)
+
       '''for''' k = 0..n * (n - 1)
 
         '''if''' (queue.at(0), queue.at(1)) <tex> \notin E</tex>                <font color = "green">// Проверяем существования ребра между первой и второй вершинами очереди</font>
 
         '''if''' (queue.at(0), queue.at(1)) <tex> \notin E</tex>                <font color = "green">// Проверяем существования ребра между первой и второй вершинами очереди</font>
 
           i = 2                                             
 
           i = 2                                             

Версия 21:09, 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]\mathtt{findHamiltonianCycle}[/math] получает на вход граф [math] G [/math] и находит гамильтонов цикл в нем.

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

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

Лемма:
Каждый раз, когда нам надо искать вершину [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].

См.также

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