Алгоритм нахождения Гамильтонова цикла в условиях теорем Дирака и Оре — различия между версиями
Novik (обсуждение | вклад) (→Описание алгоритма) |
Novik (обсуждение | вклад) (→Псевдокод) |
||
Строка 12: | Строка 12: | ||
|- | |- | ||
| | | | ||
− | g[][] - булевская матрица смежности | + | <font color = "green">// g[][] - булевская матрица смежности</font> |
− | Queue queue // создаем очередь | + | '''Queue''' queue <font color = "green">// создаем очередь</font> |
− | for i = 0 to n - 1 | + | '''for''' i = 0 '''to''' n - 1 |
− | queue.pushBack(v[i]) // добавляем в очередь все вершины графа | + | queue.pushBack(v[i]) <font color = "green">// добавляем в очередь все вершины графа</font> |
− | for k = 0 to n*(n - 1) | + | '''for''' k = 0 '''to''' n*(n - 1) <font color = "green">// пока не проделано нужное количество итераций</font> |
− | if not g[queue.at(0), queue.at(1)] // проверяем существования ребра между первой и второй вершинами очереди | + | '''if''' '''not''' g[queue.at(0), queue.at(1)] <font color = "green">// проверяем существования ребра между первой и второй вершинами очереди</font> |
i = 2 | i = 2 | ||
− | while not g[queue.at(0), queue.at(i)] | + | '''while''' '''not''' g[queue.at(0), queue.at(i)] |
− | or not g[queue.at(1), queue.at(i + 1)] // ищем индекс удовлетворяющую условию вершины | + | '''or''' '''not''' g[queue.at(1), queue.at(i + 1)] <font color = "green">// ищем индекс удовлетворяющую условию вершины</font> |
i++ | i++ | ||
− | queue.swapSubQueue(2, i) // разворачиваем часть перестановки от 2-й до найденной позиции включительно | + | queue.swapSubQueue(2, i) <font color = "green">// разворачиваем часть перестановки от 2-й до найденной позиции включительно</font> |
− | queue.pushBack(queue.top()) // Добавляем первую вершину в конец очереди | + | queue.pushBack(queue.top()) <font color = "green">// Добавляем первую вершину в конец очереди</font> |
− | queue.pop() // а из начала очереди удаляем | + | queue.pop() <font color = "green">// а из начала очереди удаляем</font> |
− | |||
|} | |} | ||
Версия 17:55, 8 ноября 2015
Содержание
Описание алгоритма
Пусть у нас есть граф теоремы Оре или теоремы Дирака, и требуется найти в нем гамильтонов цикл. Поступим следующим образом: заведем очередь и положим в нее все вершины нашего графа(не важно в каком порядке). Теперь , где , раз будем делать следующую операцию:
, удовлетворяющий условию- Если между первой (здесь и далее первая вершина - вершина в голове очереди) и второй вершиной в очереди есть ребро в графе , то перемещаем первую вершину в конец очереди и переходим к следующей итерации.
- Если между первой и второй вершиной в очереди ребра нет, то найдем вершину теорема Оре, либо теорема Дирака, то такая вершина обязательно найдется; чуть позже мы это докажем явно). После чего поменяем в очереди местами вершины и , и , и , и так далее, пока (то есть пробегает все значения от 0 до значения заданного неравенством). Теперь у нас появилось ребро между первой и второй вершинами в очереди (теперь вторая вершина, это та, которая была до разворота на -й позиции), а также, гарантированно существует ребро между -й и -й вершинами очереди. После этого, так же как и в первом случае, оправляем первую вершину в конец очереди. , где , такую что, ребра (так как у нас для графа выполнена либо
Таким образом после
итераций, мы получаем последовательность (вершины лежащие в очереди), где любые 2 соседние вершины соединены ребром, все вершины графа находятся в этой последовательности, и более того, каждая ровно один раз, а также существует ребро между последней и первой вершинами очереди, а это и значит, что мы решили поставленную задачу.Псевдокод
// g[][] - булевская матрица смежности Queue queue // создаем очередь for i = 0 to n - 1 queue.pushBack(v[i]) // добавляем в очередь все вершины графа for k = 0 to n*(n - 1) // пока не проделано нужное количество итераций if not g[queue.at(0), queue.at(1)] // проверяем существования ребра между первой и второй вершинами очереди i = 2 while not g[queue.at(0), queue.at(i)] or not g[queue.at(1), queue.at(i + 1)] // ищем индекс удовлетворяющую условию вершины i++ queue.swapSubQueue(2, i) // разворачиваем часть перестановки от 2-й до найденной позиции включительно queue.pushBack(queue.top()) // Добавляем первую вершину в конец очереди queue.pop() // а из начала очереди удаляем |
Доказательство алгоритма
Для доказательства корректности алгоритма достаточно показать:
- Каждый раз, когда нам надо искать вершину , где , такую что , такая вершина действительно существует.
- После итераций между каждой парой соседних вершин очереди существует ребро.
Докажем первое. Рассмотрим множество теоремы Оре или теоремы Дирака). Из этого следует, что , а это и значит, что искомая вершина существует.
, состоящее из индексов вершин, смежных с , и множество , индексов вершин смежных с . Заметим, что , а , тогда , а значит , в то же время (по условиюДля доказательства второй части, достаточно заметить, что каждую итерацию алгоритма, мы, в случае отсутствия ребра, между
и увеличиваем количество пар соседних в очереди вершин, между которыми есть ребро, как минимум на 1 (это прямое следствие условия поиска нужной вершины, в случае отсутствия ребра), для поиска такой пары требуется не более итераций. Таких пар изначально не более , откуда следует, что после итераций, второе условие будет выполнено.Сложность алгоритма
Алгоритм работает за
. Действительно, количество итераций внешнего цикла всегда равно . Поиск вершины, удовлетворяющей заданному условию тоже работает за , а таких поисков будет осуществлено не более чем , итого время работы .