Участник:Kabanov — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м
Строка 1: Строка 1:
{{nohate}}
+
4 Алгоритм K*
== Определение ==
+
Также как и алгоритм Eppstein, K* выполняет поиск пути на графе G и использует граф путей P(G). Граф путей ищется с помощью алгоритма Дейкстры для того, чтобы пути s-t в виде последовательности запасных путей. Общий принцип работы алгоритма K* следующий:
{{Определение
+
1) K* применяет A* на графе G вместо обратного алгоритма Дейкстры, который использует алгоритм Eppstein.
|definition=
+
2) Мы запускаем A* на G и Дейкстру на P(G) поочередно порядке, который позволяет Дейкстре доставить пути решение до заверешения поиска на G алгоритма A*.
'''Подразбиение Делоне множества точек''' — такое разбиение выпуклой оболочки множества точек на множество выпуклых фигур, что в окружности, описанной вокруг любой из фигур, не  находится никаких точек из множества.
 
}}
 
{{Определение
 
|definition=
 
'''Триангуляция Делоне множества точек''' — триангуляция, являющаяся подразбиением Делоне.
 
}}
 
  
== Существование триангуляции Делоне ==
+
4.1 Поиск A* на G.
{{Лемма
+
K* применяет A* к входному графу G для того, чтобы определить дерево поиска T.
|about=1
+
В отличие от алгоритма Eppstein в K* A* применяется к графу G в прямом порядке из-за чего коренем дерева T является вершина s. Это необходимо для того, чтобы была возможность работать c неявным описанием графа G через функцию successor. На протяжении статьи будем считать граф G конечным, если не будет сказано иначе. Заметим, что А* корректен на конечных графах. Будем следовать литературному соглашению, предполагая, что стоимость бесконечного пути неограниченна.
|statement=
 
Окружность, спроецированная на параболоид, находится в одной плоскости. Все точки, лежащие внутри окружности, будут лежать под этой плоскостью. Точки, лежащие вне окружности, будут лежать над плоскостью.
 
}}
 
{{Теорема
 
|statement=
 
Подразбиение Делоне существует, причём для каждого набора точек оно единственно.
 
|proof=
 
Спроецируем все точки на параболоид и построим выпуклую оболочку.
 
  
Все грани выпуклой оболочки окажутся внутри параболоида из-за его выпуклости. При этом точки лежат на параболоиде. Поэтому не найдётся точек, которые будут лежать за гранями выпуклой оболочки. То есть все точки, спроецированные на параболоид, будут принадлежать выпуклой оболочке.
+
4.2 Стоимость объезда
 +
Для ребра (u, v) стоимость объезда \delta(u, v) является стоимостью ущерба из-за взятия ребра объезда (u, v) в сравнении с кратчайшим путем s-t через v. Ни длина кратчайшего пути s-t через v, ни длина пути s-t, включающего запапасные ребра (u, v) не известны, когда A* обнаруживает (u, v). Обе длины могут быть оценены с помощью функции оценки f, которая использует эвристическую функцию h. Путь f(v) будет f-значением с соответствии с деревом поиска T и f_u(v) будет f-значанием в соответствии  с родителем u, т.е. f_u(v) = g(u) + c(u, v) + h(v). \delta(u, v) может быть определена так:
 +
 +
\delta(u, v) = f_u(v) - f(v) = g(u) + c(u, v) + h(v) - g(v) - h(v) = g(u) + c(u, v) - g(v)
  
По лемме 1 очевидно, что внутри окружностей, описанных вокруг проекций граней выпуклой оболочки, не будет лежать никаких точек. Значит, проекции граней — фигуры подразбиения Делоне. Значит, такое подразбиение существует.  
+
Заметим, что \delta(u, v) дает точную объездную метрику, поскольку функция оценки h-значения не появляется в определении функции \delta(u, v).
  
Из единственности выпуклой оболочки следует, что такое подразбиение единственно.
+
4.3 Структура графе путей
}}
+
Структура графа путей P(G) довольно сложная. В принципе, P(G) будет ориентированным графом, вершины которого соответствуют ребрам в исходном графе G. Он будет организован как коллекция взаимосвязанных куч (англ. heap). 2 бинарные минимальные кучи присвоены к каждой вершине v в графе G, которые называются входящей кучей H_{in}(v) и деревянной кучей H_{T}(v). Эти кучи являются базисом P(G). Как мы покажем далее, испльзование этих куч также играет главную роль в поддержании асимптотической сложности K*, также как в EA и LVEA.
 +
Входящая куча H_{in}(v) содержит узлы для каждого запасного ребра к вершине v, которые до сих пор были обнаружены A*. Узлы H_{in}(v) будут упорядочены в соответствии с \delta-значением соответствующих переходов. Узел владеющий ребром с минимальной стоимостью ущерба будет расположен на вершине кучи. Мы ограничим структуру кучи H_{in}(v) таким образом, что её корень в отличие от остальных узлов, имеет не более 1 ребенка. Мы обозначим его root_{in}(v).
  
== Критерий Делоне для рёбер ==
+
Деревянная куча H_{T}(v) для произвольной вершины v строится следующим образом. Если v - стартовая вершина, т.е. v=s, то H_{T}(v) будет изначально пустой кучей. Затем узел в неё будет добавлен root_{in}(s), если H_{in}(s) не пустая. Если v не стартовая вершина, то пусть вершина u будет родителем вершины v в дереве поиска T. Мы можем представить, что H_{T}(v) конструируется как копия H_{T}(u), в которую добавлен root_{in}(v). Если H_{in}(v) пустая, то H_{T}(v) идентична H_{T}(u). Однако, для экономии памяти мы создаем только дешевую копию H_{T}(u). Это осуществляется через создание копий только узлов кучи, которые лежат на обновленном пути H_{T}(u). Оставшаяся часть H_{T}(u) не копируется. Другими словами, root_{in}(v) вставляется в H_{T}(u) неразрушающим путем так, что структура H_{T}(u) сохраняется. В куче H_{T}(v) 1 или 2 ребенка могут быть присоединены к root_{in}(v). К тому же, root_{in}(v) хранит только 1 собственного ребенка из H_{in}(v). Мы обозначим корень H_{T}(v) как R(v).
{{Определение
 
|definition='''Критерий Делоне для ребра''': на ребре можно построить такую окружность, что внутри неё не будет лежать никаких точек.
 
}}
 
{{Лемма
 
|about=2
 
|statement=Триангуляции Делоне принадлежат те и только те рёбра (с поправкой на точки, лежащие на одной окружности), которые удовлетворяют критерию Делоне.
 
|proof=
 
[[Файл:Good edges.png|200px|right]]
 
То, что для рёбер, принадлежащих триангуляции Делоне, выполняется критерий Делоне для рёбер, очевидно (вокруг каждого ребра можно описать окружность, проходящую через противолежащую ему точку в смежном треугольнике, причём в окружности не будет никаких точек по критерию Делоне).
 
  
Докажем, что если для ребра выполняется критерий Делоне, то оно принадлежит триангуляции Делоне.
+
Обратимся к ребрам, которые берут начало из входящих или деревянных куч, как к кучным ребрам. Сформулируем следующую лемму.
 +
Лемма 1. Все узлы, которые достижимы из R(v) через кучные ребра для каждой вершины v, формируют тернарную кучу, упорядоченную в соответствии с \delta-значением. Мы назовем такую кучу графовой кучей вершины v и обозначим его как H_{G}(v).
  
Предположим, что это ребро (назовём его <tex>AB</tex>) не принадлежит триангуляции Делоне. Тогда существует пересекающее его ребро <tex>CD</tex>, принадлежащее триангуляции. Рассмотрим четырёхугольник <tex>ACBD</tex>. Точки <tex>C</tex> и <tex>D</tex> лежат вне окружности, построенной на <tex>AB</tex> как на хорде, поэтому сумма углов <tex>C</tex> и <tex>D</tex> меньше 180°. Аналогичным образом доказывается, что сумма углов <tex>A</tex> и <tex>B</tex> тоже меньше 180°. Значит, сумма углов четырёхугольника <tex>ACBD</tex> меньше 360°, что невозможно. Противоречие. Значит, ребро <tex>AB</tex> принадлежит триангуляции Делоне.
+
...
}}
 
  
== Локальный критерий Делоне ==
+
Финальная структура P(G) получется из входящих и деревянных куч следующим образом. К каждому узлу n из P(G), несущему ребро (u,v), мы присоединим указатель, ссылающийся на R(u), который является корневым узлом H_{T}(u). Мы назовем такие указатели кросс-ребрами, в то время как указатели, возникающие из куч названы кучными ребрами, как упоминалось раньше. Более того, мы добавим специальный узел R в P(G) с одним выходящим кросс-ребром к R(t).
{{Определение
 
|definition='''Локальный критерий Делоне''': для пары треугольников, которым принадлежит это ребро, выполняется критерий Делоне (то есть вершина, противолежащая ребру в одном треугольнике, не лежит в окружности, описанной вокруг другого, и наоборот).
 
}}
 
Будем называть '''хорошими''' те рёбра, для которых выполняется локальный критерий Делоне.
 
{{Лемма
 
|about=3
 
|id=fliplemma
 
|statement=
 
Из двух рёбер, которые можно провести для пары треугольников, как минимум одно хорошее.
 
|proof=
 
[[Файл:Bad edges.png|200px|right]]
 
Предположим, что это не так, то есть оба ребра (назовём их <tex>AB</tex> и <tex>CD</tex>) плохие. Рассмотрим четырёхугольник <tex>ACBD</tex> и окружность, описанную вокруг треугольника <tex>ABC</tex>. Точка <tex>D</tex> лежит внутри этой окружности, значит, сумма углов <tex>C</tex> и <tex>D</tex> больше 180°. Аналогично доказывается, что сумма углов <tex>A</tex> и <tex>B</tex> больше 180°. Значит, сумма углов четырёхугольника <tex>ACBD</tex> больше 360°, что невозможно.
 
}}
 
{{Лемма
 
|about=4
 
|statement=
 
Если для всех рёбер выполняется локальный критерий Делоне, то выполняется и глобальный критерий Делоне.
 
|proof=
 
[[Файл:Bad triangle.png|200px|right]]
 
Пример:Все рёбра треугольника хорошие, но описанная окружность содержит точки.
 
  
Предположим, что это не так, то есть все рёбра хорошие, но существуют треугольники, описанная окружность которых содержат какие-либо точки триангуляции. Возьмём какую-либо конфликтную точку <tex>E</tex>. Рассмотрим такой треугольник <tex>ABC</tex> из тех, в описанную окружность которых попадает <tex>E</tex>, что угол <tex>BEC</tex> максимален, если <tex>BC</tex> — ближайшая к точке <tex>E</tex> сторона. Пусть треугольник <tex>BDC</tex> — смежный с <tex>ABC</tex>.
+
Более того, мы определим весовую функцию \Delta на ребрах из P(G). Пусть (n, n') обозначает ребро в P(G), и пусть e и e' обозначают ребра из G соответствующие узлам n и n'. Тогда определим \Delta(n,n') следующим образом:
  
Докажем, что точка <tex>E</tex> лежит в окружности, описанной вокруг <tex>BDC</tex>. Предположим, что это не так. Посмотрим на окружность, описанную вокруг треугольника <tex>ABC</tex>: <tex>\angle BAC + \angle BEC > 180^\circ</tex> и <tex>\angle BAC + \angle BDC < 180^\circ</tex>. Если точка <tex>E</tex> не лежит в окружности, описанной вокруг треугольника <tex>BDC</tex>, то <tex>\angle BEC < \angle BDC</tex>, что противоречит предыдущим двум неравенствам.
+
\Delta(n,n')=\delta(e') - \delta(e) если (n,n') кучное ребро
 +
\Delta(n,n')=\delta(e') если (n,n') кросс-ребро.
  
Очевидно, что угол <tex>BED</tex> больше, чем угол <tex>BEC</tex>. При этом точка <tex>E</tex> лежит в окружности, описанной вокруг <tex>BDC</tex>. Значит, при выборе треугольника нужно было взять не <tex>ABC</tex>, а <tex>BDC</tex>. Противоречие.
+
Лемма 1 подразумевает, что куча упорядоченная в соответствии с \delta-значанием поддерживается по любому кучному ребру из P(G). Эта упорядочивание кучи подразумевает, что \Delta(n,n') неотрицательна для любого кучного ребра (n,n'). Следовательно, \Delta также неотрицательна, т.е. \Delta(n,n') >= 0 для любого ребра (n,n') в P(G). Стоимость пути \sigma, т.е. C_{P(G)}(\sigma) равна \sum_{e \in \sigma}\Delta(e). 
}}
 
  
== Динамическая триангуляция ==
+
...
{{Определение
 
|definition=
 
Рассмотрим пару смежных треугольников. Рёбра этих треугольников образуют четырёхугольник с проведённой в нём диагональю. Операция замены этой диагонали на другую называется '''flip''' ('''флип''').
 
}}
 
[[Файл:Flip.png|200px|thumb|right|Красное ребро — до флипа, синее — после]]
 
Из [[#fliplemma|леммы 3]] следует, что если ребро плохое, то флип сделает его хорошим.
 
{{Лемма
 
|about=5
 
|statement=Флип плохого ребра уменьшает разность объёмов параболоида и триангуляции, спроецированной на него.
 
|id=volumelemma
 
|proof=
 
Рассмотрим два таких смежных треугольника, что ребро между ними является плохим. Спроецируем их на параболоид. Четыре точки, принадлежащие смежным треугольникам, при проекции на параболоид образуют тетраэдр.
 
  
Проведём через какой-нибудь из двух треугольников плоскость. Вершина, противолежащая основанию тетраэдра, являющегося этим треугольником, лежит ниже этой плоскости (так как не выполняется локальный критерий Делоне), то есть тетраэдр лежит ниже тела, образующегося при проекции всей триангуляции на параболоид.
+
Лемма 2. Пусть n будет узлов графовой кучи H_{G}(w) для какой-нибудь вершины w. Пусть (u,v) будет ребром связанным с n. Тогда существует путь в дереве поиска T из v в w.
  
После флипа станет выполняться локальный критерий Делоне, то есть тело станет включать в себя тетраэдр. Поэтому после флипа плохого ребра объём тела увеличится на объём этого тетраэдра.
+
...
}}
 
{{Лемма
 
|about=6
 
|statement=
 
Флипами можно достичь хорошей триангуляции за конечное время.
 
|proof=
 
Всего триангуляций заданного множества точек конечное число, и среди них есть триангуляция Делоне. Последовательность флипов плохих рёбер триангуляции образует такую последовательность триангуляций, что разность объёмов параболоида и спроецированной на него триангуляции убывает ([[#volumelemma|по лемме 5]]). Эта последовательность конечна (при этом последней в последовательности является триангуляция Делоне), значит, число флипов, требуемых для достижения триангуляции Делоне, тоже конечно.
 
}}
 
{{Лемма
 
|about=7
 
|statement=
 
Если в триангуляцию Делоне вставить точку в некоторый треугольник и соединить его вершины с этой точкой, то получившиеся рёбра будут хорошими.
 
|id=newedgeslemma
 
|proof=
 
[[Файл:Good edge.png|200px|thumb|right|Точка V вставлена в треугольник ABC]]
 
Предположим, точка была вставлена не на ребро. Рассмотрим любое из рёбер — пусть это будет ребро <tex>VC</tex>. Проведём окружность, описывающую треугольник <tex>ABC</tex>. По критерию Делоне в ней не будет никаких точек триангуляции. На ребре <tex>VC</tex> можно построить окружность, изнутри касающуюся окружности, описанной вокруг треугольника. В ней тоже нет никаких точек. Значит, для <tex>VC</tex> выполняется критерий Делоне для рёбер, значит, ребро должно принадлежать триангуляции с добавленной точкой <tex>V</tex>, значит, оно хорошее.
 
  
Случай, когда точка вставляется на ребро, рассматривается аналогично.
+
4.4 Алгоритмическая структура K*
}}
+
Алгоритмический принцип K* следующий. Будем запускать алгоритмы Дейкстры и A* на G с чередованием. Сначала, мы запустим A* на G пока вершина t не будет выбрана из очереди для рассмотрения. Затем, вы запустим алгоритмы Дейкстры на доступной части P(G). Каждый узел рассмотрел Дейкстрой представляет путь решения. Если точнее, то путь \sigma в P(G), по которому Дейкстра достигла этого узла является решением. Путь s-t может быть построен из \sigma за линейное время путем вычисления последовательности запасных ребер seq(\sigma) и затем s-t пути из неё. Если Дейкстра находит k кратчайших путей, то K* завершается успешно. Иначе, A* возобновляется для исследования большей части G. Это приводит к росту P(G), на котором алгоритм Дейкстры затем будет возобновлен. Мы будем повторять этот процесс до тех пор, пока алгоритм Дейкстры не найдет k кратчайших путей.  
=== Вставка точки ===
+
Алгоритм 1 содержит псевдокод K*. Код с 8 по 25 строчку образует главный цикл K*. Цикл завершается, когда очереди обоих алгоритмов А* и Дейкстры пусты. До 8 строчки выполняет некоторые подготовительные вещи. После инициализации, А* запускает на 5 строчке пока вершина t не будет выбрана им для рассмотрения, в этом случае кратчайший путь s-t будет найден. Если t не достигнута, то алгоритм завершается без решения. Отметим, что он не завершится на бесконечных графах. Иначе, алгоритм добавляет специальную вершину R, которая назначена корнем P(G), в поисковую очередь алгоритма Дейкстры. Затем, K* входит в главный цикл.
==== Вставка точки, лежащей внутри триангуляции ====
+
K* поддерживает механизм планирования для контролирования, когда A* или Дейкстра будет возобновлены. Если очередь из A* не пуста, что означает, что А* ещё не завершил исследования всего графа G, то Дейкстра возобновляется тогда и только тогда, когда g(t) + d <= f(u). Значение d является максимальным d-значением среди всех successor-ов головы поисковой очереди n алгоритма Дейкстры. Вершина u является головой поисковой очереди A*. Напомним, что d - функция расстояния, используемая в алгоритме Дейкстры.
[[Файл:Insert in triangle.png|200px|thumb|left|Вставка в треугольник]]
 
[[Файл:Insert on edge.png|200px|thumb|right|Вставка на ребро]]
 
 
 
Для начала локализуемся: поймём, в каком фейсе лежит точка (или на каком ребре).
 
 
 
Если точка лежит внутри фейса, добавляем три ребра, сам фейс превращаем в один из новых смежных с вставляемой точкой и добавялем ещё два фейса.
 
 
 
Если же точка лежит на ребре, два смежных с ребром фейса превращаем в два новых, добавляем ещё два, а так же превращаем ребро, на которое вставляется точка, в ребро, которое заканчивается в этой точке, и вставляем три новых.
 
 
 
Итого у нас появилось несколько новых рёбер. Они все хорошие (по [[#newedgeslemma|лемме 7]]), плохими могут оказаться только рёбра, противолежащие вставленной точке. Флипаем рёбра, пока триангуляция не станет хорошей.
 
 
 
==== Вставка точки, лежащей снаружи триангуляции ====
 
Представим, что вне триангуляции — бесконечные треугольники, основания которых — рёбра выпуклой оболочки триангуляции, а противолежащая ребру вершина — это бесконечно удалённая точка. Тогда понятно, что вставка точки, не лежащей в триангуляции, сведётся к вставке точки внутрь триангуляции, если мы научимся обрабатывать бесконечные фейсы.
 
 
 
Бесконечно удалённая точка имеет координаты <tex>(0,0,1,0)</tex> (последняя координата — однородная).
 
 
 
Тогда проверка на то, является ли хорошим ребро, инцидентное бесконечно удалённой точке, упрощается:
 
<tex>
 
\begin{vmatrix}
 
a_x & a_y & a_x^2 + a_y^2 & 1 \\
 
b_x & b_y & b_y^2 + b_y^2 & 1 \\
 
c_x & c_y & c_x^2 + c_y^2 & 1 \\
 
0  & 0  & 1            & 0
 
\end{vmatrix} = \begin{vmatrix}
 
a_x & a_y & 1 \\
 
b_x & b_y & 1 \\
 
c_x & c_y & 1
 
\end{vmatrix}
 
</tex>, то есть достаточно проверить поворот трёх остальных точек образованного двумя бесконечными треугольниками четырёхугольника.
 
 
 
Проверка, принадлежит ли точка бесконечному треугольнику, тоже проста: нужно, чтобы из точки было видно ребро, противолежащее бесконечно удалённой точке, в бесконечном треугольнике. Это проверяется предикатом поворота.
 
 
 
==== Время работы ====
 
{{Лемма
 
|about=8
 
|statement=
 
При вставке точки будут флипаться только рёбра, противолежащие вставленной точке.
 
|proof=
 
[[Файл:Flip edges.png|400px|thumb|right|V — вставленная точка, ребро AC — плохое]]
 
Доказательство по индукции.
 
 
 
База. По [[#newedgeslemma|лемме 7]] изначально не будут флипаться новые рёбра, инцидентные точке, то есть плохими могут оказаться только рёбра, противолежащие точке.
 
 
 
Переход. Рассмотрим, что произойдёт с противолежащим точке <tex>V</tex> ребром <tex>AC</tex> после флипа, если оно плохое. До вставки точки <tex>V</tex> для триангуляции выполнялся глобальный критерий Делоне, поэтому в окружности, описанной вокруг треугольника <tex>ACD</tex>, не будет лежать никаких точек, кроме точки <tex>V</tex>. Можно построить окружность, касающуюся её изнутри в точке <tex>D</tex> и проходящую через точку <tex>V</tex>. В ней тоже не окажется никаких точек, так как она касается изнутри. Значит, для ребра <tex>VD</tex> выполняется критерий Делоне. Значит, после флипа ребро <tex>AC</tex> уже не будет флипаться. Так как для рёбер <tex>AV</tex> и <tex>CV</tex> выполняется критерий Делоне, то плохими после флипа могут стать только рёбра <tex>AD</tex> и <tex>CD</tex> — то есть рёбра, противолежащие точке <tex>V</tex>.
 
}}
 
{{Лемма
 
|about=9
 
|statement=
 
Средняя степень вершины после вставки её в триангуляцию Делоне равна <tex>O(1)</tex>.
 
|id=deglemma
 
|proof=
 
Предположим, что мы вставляем <tex>i+1</tex>-ую точку из последовательности из <tex>n</tex> точек. Рассмотрим все перестановки из этих <tex>i+1</tex> точек, означающие порядок вставки этих точек. Всего таких перестановок <tex>(i+1)!</tex>. Тогда средняя степень последней вершины среди перестановок равна:
 
 
 
<tex>E(\operatorname{deg}(v_{i+1}))=\frac {\sum_{p=perm(v_1, v_2, ..., v_{i+1})} \operatorname{deg} (p[i+1])} {(i+1)!}</tex>
 
 
 
Каждая из <tex>i+1</tex> вершин побывает последней ровно <tex>i!</tex> раз, поэтому:
 
 
 
<tex>E(\operatorname{deg} (v_{i+1}))=\frac {\sum_{k=0}^{i} i! \operatorname{deg} (v_k)} {(i+1)!} = \frac {\sum_{k=0}^i \operatorname{deg}(v_k)} {i+1} = \frac {O(i+1)} {i+1} = O(1)</tex>
 
}}
 
{{Теорема
 
|statement=
 
При вставке точки в триангуляцию Делоне в среднем придётся сделать <tex>O(1)</tex> флипов.
 
|id=flipnumberlemma
 
|proof=
 
Все флипнутые рёбра окажутся инцидентными вставленной точке (по лемме 8), а [[#deglemma|степень вершины — <tex>O(1)</tex> (по лемме 9)]]. Поэтому будет сделано <tex>O(1)</tex> флипов.
 
}}
 
Так как среднее число флипов — <tex>O(1)</tex>, то время вставки целиком зависит от времени локализации.
 
 
 
=== Удаление точки ===
 
==== Алгоритм ====
 
При удалении точки получится {{Acronym|звёздный многоугольник, который можно затриангулировать за линию|Общеизвестный факт}}. При этом все рёбра, полученные в результате триангуляции звёздного многоугольника, могут оказаться плохими, поэтому необходимо пройтись по ним и пофлипать, если нужно.
 
==== Время работы ====
 
{{Acronym|Средняя степень вершины в триангуляции — <tex>O(1)</tex>|Общеизвестный факт}}, поэтому триангуляция звёздного многоугольника будет тоже за <tex>O(1)</tex>. Новых рёбер получится <tex>O(1)</tex>, проверить их на локальный критерий Делоне и пофлипать тоже можно за <tex>O(1)</tex>. Итого удаление точки работает за <tex>O(1)</tex>.
 
 
 
== Constraints ==
 
{{Определение
 
|definition=
 
'''Констрейнты''' — рёбра, которые нельзя флипать.
 
}}
 
{{Утверждение
 
|statement=
 
Хорошая триангуляция с констрейнтом может быть хорошей с точностью до видимости через констрейнт.
 
}}
 
=== Вставка ===
 
[[Файл:Constraint.png|400px|thumb|right|Красным выделен вставляемый констрейнт]]
 
Смотрим на список рёбер, пересечённых ещё не вставленным констрейнтом, и флипаем их. Последнее флипнутое ребро и будет констрейнтом {{Acronym|(по понятным причинам)|Рёбра, пересечённые констрейнтом, после флипа будут начинаться в той же точке, что и констрейнт, а заканчиваться в точке, в которой начинается ещё одно пересекающее ребро. Последнее же ребро будет начинаться и заканчиваться в начале и конце констрейнта}}, после флипа пометим его как констрейнт. Затем флипаем всё, что могло стать плохим (кроме констрейнта), пока триангуляция вновь не станет хорошей.
 
=== Удаление ===
 
Аналогично: помечаем ребро как не-констрейнт и флипаем, пока не дойдём до хорошей триангуляции.
 

Версия 16:24, 4 августа 2015

4 Алгоритм K* Также как и алгоритм Eppstein, K* выполняет поиск пути на графе G и использует граф путей P(G). Граф путей ищется с помощью алгоритма Дейкстры для того, чтобы пути s-t в виде последовательности запасных путей. Общий принцип работы алгоритма K* следующий: 1) K* применяет A* на графе G вместо обратного алгоритма Дейкстры, который использует алгоритм Eppstein. 2) Мы запускаем A* на G и Дейкстру на P(G) поочередно порядке, который позволяет Дейкстре доставить пути решение до заверешения поиска на G алгоритма A*.

4.1 Поиск A* на G. K* применяет A* к входному графу G для того, чтобы определить дерево поиска T. В отличие от алгоритма Eppstein в K* A* применяется к графу G в прямом порядке из-за чего коренем дерева T является вершина s. Это необходимо для того, чтобы была возможность работать c неявным описанием графа G через функцию successor. На протяжении статьи будем считать граф G конечным, если не будет сказано иначе. Заметим, что А* корректен на конечных графах. Будем следовать литературному соглашению, предполагая, что стоимость бесконечного пути неограниченна.

4.2 Стоимость объезда Для ребра (u, v) стоимость объезда \delta(u, v) является стоимостью ущерба из-за взятия ребра объезда (u, v) в сравнении с кратчайшим путем s-t через v. Ни длина кратчайшего пути s-t через v, ни длина пути s-t, включающего запапасные ребра (u, v) не известны, когда A* обнаруживает (u, v). Обе длины могут быть оценены с помощью функции оценки f, которая использует эвристическую функцию h. Путь f(v) будет f-значением с соответствии с деревом поиска T и f_u(v) будет f-значанием в соответствии с родителем u, т.е. f_u(v) = g(u) + c(u, v) + h(v). \delta(u, v) может быть определена так:

\delta(u, v) = f_u(v) - f(v) = g(u) + c(u, v) + h(v) - g(v) - h(v) = g(u) + c(u, v) - g(v)

Заметим, что \delta(u, v) дает точную объездную метрику, поскольку функция оценки h-значения не появляется в определении функции \delta(u, v).

4.3 Структура графе путей Структура графа путей P(G) довольно сложная. В принципе, P(G) будет ориентированным графом, вершины которого соответствуют ребрам в исходном графе G. Он будет организован как коллекция взаимосвязанных куч (англ. heap). 2 бинарные минимальные кучи присвоены к каждой вершине v в графе G, которые называются входящей кучей H_{in}(v) и деревянной кучей H_{T}(v). Эти кучи являются базисом P(G). Как мы покажем далее, испльзование этих куч также играет главную роль в поддержании асимптотической сложности K*, также как в EA и LVEA. Входящая куча H_{in}(v) содержит узлы для каждого запасного ребра к вершине v, которые до сих пор были обнаружены A*. Узлы H_{in}(v) будут упорядочены в соответствии с \delta-значением соответствующих переходов. Узел владеющий ребром с минимальной стоимостью ущерба будет расположен на вершине кучи. Мы ограничим структуру кучи H_{in}(v) таким образом, что её корень в отличие от остальных узлов, имеет не более 1 ребенка. Мы обозначим его root_{in}(v).

Деревянная куча H_{T}(v) для произвольной вершины v строится следующим образом. Если v - стартовая вершина, т.е. v=s, то H_{T}(v) будет изначально пустой кучей. Затем узел в неё будет добавлен root_{in}(s), если H_{in}(s) не пустая. Если v не стартовая вершина, то пусть вершина u будет родителем вершины v в дереве поиска T. Мы можем представить, что H_{T}(v) конструируется как копия H_{T}(u), в которую добавлен root_{in}(v). Если H_{in}(v) пустая, то H_{T}(v) идентична H_{T}(u). Однако, для экономии памяти мы создаем только дешевую копию H_{T}(u). Это осуществляется через создание копий только узлов кучи, которые лежат на обновленном пути H_{T}(u). Оставшаяся часть H_{T}(u) не копируется. Другими словами, root_{in}(v) вставляется в H_{T}(u) неразрушающим путем так, что структура H_{T}(u) сохраняется. В куче H_{T}(v) 1 или 2 ребенка могут быть присоединены к root_{in}(v). К тому же, root_{in}(v) хранит только 1 собственного ребенка из H_{in}(v). Мы обозначим корень H_{T}(v) как R(v).

Обратимся к ребрам, которые берут начало из входящих или деревянных куч, как к кучным ребрам. Сформулируем следующую лемму. Лемма 1. Все узлы, которые достижимы из R(v) через кучные ребра для каждой вершины v, формируют тернарную кучу, упорядоченную в соответствии с \delta-значением. Мы назовем такую кучу графовой кучей вершины v и обозначим его как H_{G}(v).

...

Финальная структура P(G) получется из входящих и деревянных куч следующим образом. К каждому узлу n из P(G), несущему ребро (u,v), мы присоединим указатель, ссылающийся на R(u), который является корневым узлом H_{T}(u). Мы назовем такие указатели кросс-ребрами, в то время как указатели, возникающие из куч названы кучными ребрами, как упоминалось раньше. Более того, мы добавим специальный узел R в P(G) с одним выходящим кросс-ребром к R(t).

Более того, мы определим весовую функцию \Delta на ребрах из P(G). Пусть (n, n') обозначает ребро в P(G), и пусть e и e' обозначают ребра из G соответствующие узлам n и n'. Тогда определим \Delta(n,n') следующим образом:

\Delta(n,n')=\delta(e') - \delta(e) если (n,n') кучное ребро \Delta(n,n')=\delta(e') если (n,n') кросс-ребро.

Лемма 1 подразумевает, что куча упорядоченная в соответствии с \delta-значанием поддерживается по любому кучному ребру из P(G). Эта упорядочивание кучи подразумевает, что \Delta(n,n') неотрицательна для любого кучного ребра (n,n'). Следовательно, \Delta также неотрицательна, т.е. \Delta(n,n') >= 0 для любого ребра (n,n') в P(G). Стоимость пути \sigma, т.е. C_{P(G)}(\sigma) равна \sum_{e \in \sigma}\Delta(e).

...

Лемма 2. Пусть n будет узлов графовой кучи H_{G}(w) для какой-нибудь вершины w. Пусть (u,v) будет ребром связанным с n. Тогда существует путь в дереве поиска T из v в w.

...

4.4 Алгоритмическая структура K* Алгоритмический принцип K* следующий. Будем запускать алгоритмы Дейкстры и A* на G с чередованием. Сначала, мы запустим A* на G пока вершина t не будет выбрана из очереди для рассмотрения. Затем, вы запустим алгоритмы Дейкстры на доступной части P(G). Каждый узел рассмотрел Дейкстрой представляет путь решения. Если точнее, то путь \sigma в P(G), по которому Дейкстра достигла этого узла является решением. Путь s-t может быть построен из \sigma за линейное время путем вычисления последовательности запасных ребер seq(\sigma) и затем s-t пути из неё. Если Дейкстра находит k кратчайших путей, то K* завершается успешно. Иначе, A* возобновляется для исследования большей части G. Это приводит к росту P(G), на котором алгоритм Дейкстры затем будет возобновлен. Мы будем повторять этот процесс до тех пор, пока алгоритм Дейкстры не найдет k кратчайших путей. Алгоритм 1 содержит псевдокод K*. Код с 8 по 25 строчку образует главный цикл K*. Цикл завершается, когда очереди обоих алгоритмов А* и Дейкстры пусты. До 8 строчки выполняет некоторые подготовительные вещи. После инициализации, А* запускает на 5 строчке пока вершина t не будет выбрана им для рассмотрения, в этом случае кратчайший путь s-t будет найден. Если t не достигнута, то алгоритм завершается без решения. Отметим, что он не завершится на бесконечных графах. Иначе, алгоритм добавляет специальную вершину R, которая назначена корнем P(G), в поисковую очередь алгоритма Дейкстры. Затем, K* входит в главный цикл. K* поддерживает механизм планирования для контролирования, когда A* или Дейкстра будет возобновлены. Если очередь из A* не пуста, что означает, что А* ещё не завершил исследования всего графа G, то Дейкстра возобновляется тогда и только тогда, когда g(t) + d <= f(u). Значение d является максимальным d-значением среди всех successor-ов головы поисковой очереди n алгоритма Дейкстры. Вершина u является головой поисковой очереди A*. Напомним, что d - функция расстояния, используемая в алгоритме Дейкстры.