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

Материал из Викиконспекты
Перейти к: навигация, поиск
(Описание алгоритма: тыц)
м (Описание алгоритма)
Строка 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}_i \mathrm{v}_{i+1} </tex>, начиная с пары <tex> \mathrm{v}_1 \mathrm{v}_2 </tex>.  
+
Алгоритм находит [[Гамильтоновы графы|гамильтонов цикл]] в [[Основные определения теории графов#Неориентированные графы|неориентированном графе]] <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 < n</tex>.  
  
 
* Если между ними есть ребро, то переходим к следующей паре вершин <tex> \mathrm{v}_{i+1} \mathrm{v}_{i+2}</tex>.  
 
* Если между ними есть ребро, то переходим к следующей паре вершин <tex> \mathrm{v}_{i+1} \mathrm{v}_{i+2}</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>\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>i < j </tex> то перевернем часть перестановки от <tex> i+1 </tex> до <tex> j </tex> (включительно).
 
** Если <tex>i < j </tex> то перевернем часть перестановки от <tex> i+1 </tex> до <tex> j </tex> (включительно).
 
** Если <tex> i > j </tex> обменяем в перестановке элементы на позициях <tex> (i + 1 + k)\ mod\ n </tex> и <tex> (j - k +n)\ mod\ n </tex>, где <tex>k = \overline{0, (j + n - i)\ div\ 2}</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> i > j </tex> обменяем в перестановке элементы на позициях <tex> (i + 1 + k)\ mod\ n </tex> и <tex> (j - k +n)\ mod\ n </tex>, где <tex>k = \overline{0, (j + n - i)\ div\ 2}</tex>. Например, если <tex>n = 10, i = 8, j = 1</tex>, то <tex>\mathrm{v}_9 </tex> и <tex>\mathrm{v}_1</tex> поменяются местами, а <tex>\mathrm{v}_{10}</tex> останется на месте.

Версия 18:45, 6 ноября 2013

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

Алгоритм находит гамильтонов цикл в неориентированном графе [math] \mathbb{G} = (\mathbb{V}, \mathbb{E}) [/math], если выполняются условия теоремы Оре или выполнена теорема Дирака. Рассмотрим перестановку вершин [math] \mathrm{v}_1 \mathrm{v}_2 ... \mathrm{v}_n[/math], где [math]n = | \mathbb{V} |[/math]. Если между каждой парой соседних вершин в перестановке существует ребро, то мы получили Гамильтонов цикл. В противном случае, начиная с пары [math] \mathrm{v}_1 \mathrm{v}_2 [/math], начнем последовательно рассматривать пары соседних вершин [math] \mathrm{v}_i \mathrm{v}_{i+1} [/math], пока [math]i \lt n[/math].

  • Если между ними есть ребро, то переходим к следующей паре вершин [math] \mathrm{v}_{i+1} \mathrm{v}_{i+2}[/math].
  • Если же ребра нет, то найдем такую вершину [math]\mathrm{v}_j[/math], что [math] \mathrm{v}_j \in{\mathbb{V}} \setminus \{ \mathrm{v}_i, \mathrm{v}_{i+1} \} [/math], и существуют ребра [math] \mathrm{v}_i \mathrm{v}_j[/math] и [math] \mathrm{v}_{i+1} \mathrm{v}_{j+1} [/math] (Если [math] j = n[/math] , то за [math]\mathrm{v}_{j+1}[/math] считаем [math]\mathrm{v}_{1}[/math]).
    • Если [math]i \lt j [/math] то перевернем часть перестановки от [math] i+1 [/math] до [math] j [/math] (включительно).
    • Если [math] i \gt j [/math] обменяем в перестановке элементы на позициях [math] (i + 1 + k)\ mod\ n [/math] и [math] (j - k +n)\ mod\ n [/math], где [math]k = \overline{0, (j + n - i)\ div\ 2}[/math]. Например, если [math]n = 10, i = 8, j = 1[/math], то [math]\mathrm{v}_9 [/math] и [math]\mathrm{v}_1[/math] поменяются местами, а [math]\mathrm{v}_{10}[/math] останется на месте.

Псевдокод

 for [math]v_i \in P [/math]                              //перебираем все вершины перестановки [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]\mathrm{v}_i \mathrm{v}_{i+1}[/math]. Если теперь между первыми двумя вершинами есть ребро, то можем переходить к рассмотрению следующей пары, так как в этом случае мы ничего не делаем. Если же ребра нет, то докажем, что обязательно найдется вершина [math] \mathrm{v}_j \in \mathbb{V} \setminus \{\mathrm{v}_1, \mathrm{v}_{2}\}[/math], такая что [math]\mathrm{v}_1 \mathrm{v}_j,\ \mathrm{v}_2 \mathrm{v}_{j+1} \in \mathbb{E} [/math].

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