Гамильтоновы графы — различия между версиями
(→Алгорит нахождения гамильтового цикла) |
(→Алгоритм нахождения гамильтового цикла) |
||
Строка 102: | Строка 102: | ||
* count — количество посещённых вершин | * count — количество посещённых вершин | ||
− | Приведённая процедура работает следующим образом: перебираются всё рёбра из текущей вершины в ещё не посещённые. Чтобы проверить граф на гамильтоновость, необходимо запустить процедуру из вершины с номером 0 и параметром count = 1. Если процедура возвращает true, то в массиве next будет храниться следующая вершина на гамильтоновом цикле. | + | Приведённая процедура работает следующим образом: перебираются всё рёбра из текущей вершины в ещё не посещённые. Чтобы проверить граф на гамильтоновость, необходимо запустить процедуру из вершины с номером 0 и параметром count = 1. Если процедура возвращает true, то в массиве next будет храниться следующая вершина на гамильтоновом цикле. Этот алгоритм в худшем случае перебирает <tex>(n - 1)!</tex> путей, что даёт сложность работы <tex>O(n!)</tex>. |
+ | |||
+ | Приведём алгоритм, основанный на динамическом программировании, который работает значительно быстрее. Алгоритм основан на следующей идее: будем для каждой пары из подмножества вершин и вершины считать, существует ли гамильтонов путь для этого подмножества вершин, заканчивающихся в выделенной вершине. Суммарно таких состояний будет <tex>O(n2^n)</tex>, для обсчёта каждого из них требуется <tex>O(n)</tex> времени, то есть, суммарно алгоритм работает за <tex>O(n^22^n)</tex> времени. Псевдокод, реализующий этот алгоритм, приведён ниже: | ||
+ | |||
+ | bool[][] get_dp_table(graph g): | ||
+ | int n = g.vertices | ||
+ | bool[][] result = new int[1 << n][n]; | ||
+ | for (int i = 0; i < n; i++): | ||
+ | result[1 << i][i] = true; | ||
+ | for (int i = 1; i < (1 << n); i++): | ||
+ | if (count(i) == 1): | ||
+ | continue | ||
+ | for (int j = 0; j < n; j++): | ||
+ | if ((1 << j) & i != 0): | ||
+ | for (int k = 0; k < n; k++): | ||
+ | if (k != j && (1 << k) & i != 0): | ||
+ | result[i][j] = result[(1 << j) ^ i][k] && (k; j) in g.edges | ||
+ | return result | ||
+ | |||
+ | В приведённом выше коде считаем, что n меньше количества бит в числовом типе данных, для операций над множествами используются побитовые логические операции в синтаксисе языка C. | ||
==Источники== | ==Источники== |
Версия 23:54, 17 января 2012
Содержание
Основные определения
Определение: |
Гамильтоновым путём называется простой путь, приходящий через каждую вершину графа ровно один раз. |
Определение: |
Гамильтоновым циклом называют замкнутый гамильтонов путь. |
Определение: |
Граф называется полугамильтоновым, если он содержит гамильтонов путь. |
Определение: |
Граф называется гамильтоновым, если он содержит гамильтонов цикл. |
Очевидно, что любой гамильтонов граф также и полугамильтонов.
Достаточные условия гамильтоновости графа
Теорема Дирака
Теорема: |
Если и для любой вершины неориентированного графа , то - гамильтонов граф. |
Теорема Оре
Теорема: |
Если и для любых двух различных несмежных вершин и неориентированного графа , то - гамильтонов граф. |
Теорема Редеи-Камиона
Теорема: |
Любой сильносвязный турнир - гамильтонов. |
Теорема Гуйя-Ури
Теорема: |
Пусть G - сильносвязный ориентированный граф. G - гамильтонов. |
Теорема Хватала
Теорема (Хватал): |
Пусть:
Тогда если |
Теорема Поша
Теорема: |
Пусть граф G имеет вершин. Если для всякого число вершин со степенями, не превосходящими , меньше чем , и для нечетного число вершин степени не превосходит , то G - гамильтонов граф. |
Алгоритм нахождения гамильтового цикла
Приведём два алгоритма поиска гамильтонова цикла.
bool check_hamiltonian(graph g, bool[] used, int vert, int count, int[] next): if (count == g.vertices): next[vert] = 0 return (vert; 0) in g.edges for (i = 0; i < g.vertices; i++): if (!used[i] && (vert; i) in g.edges): used[i] = true next[vert] = i if (check_hamiltonian(g, used, i, count + 1, next)): return true used[i] = false return false
- used — отметки о посещении
- vert — текущая вершина
- count — количество посещённых вершин
Приведённая процедура работает следующим образом: перебираются всё рёбра из текущей вершины в ещё не посещённые. Чтобы проверить граф на гамильтоновость, необходимо запустить процедуру из вершины с номером 0 и параметром count = 1. Если процедура возвращает true, то в массиве next будет храниться следующая вершина на гамильтоновом цикле. Этот алгоритм в худшем случае перебирает
путей, что даёт сложность работы .Приведём алгоритм, основанный на динамическом программировании, который работает значительно быстрее. Алгоритм основан на следующей идее: будем для каждой пары из подмножества вершин и вершины считать, существует ли гамильтонов путь для этого подмножества вершин, заканчивающихся в выделенной вершине. Суммарно таких состояний будет
, для обсчёта каждого из них требуется времени, то есть, суммарно алгоритм работает за времени. Псевдокод, реализующий этот алгоритм, приведён ниже:bool[][] get_dp_table(graph g): int n = g.vertices bool[][] result = new int[1 << n][n]; for (int i = 0; i < n; i++): result[1 << i][i] = true; for (int i = 1; i < (1 << n); i++): if (count(i) == 1): continue for (int j = 0; j < n; j++): if ((1 << j) & i != 0): for (int k = 0; k < n; k++): if (k != j && (1 << k) & i != 0): result[i][j] = result[(1 << j) ^ i][k] && (k; j) in g.edges return result
В приведённом выше коде считаем, что n меньше количества бит в числовом типе данных, для операций над множествами используются побитовые логические операции в синтаксисе языка C.
Источники
- Харари Ф. Теория графов: Пер. с англ. / Предисл. В. П. Козырева; Под ред. Г.П.Гаврилова. Изд. 4-е. — М.: Книжный дом "ЛИБРОКОМ", 2009. — 60 с.
- Седжвик Р. Фундаментальные алгоритмы на C++. Алгоритмы на графах. — СПб: ООО «ДиаСофтЮП», 2002.
- Гамильтонов граф