<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=176.114.249.43&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=176.114.249.43&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/176.114.249.43"/>
		<updated>2026-06-11T18:40:57Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%B5_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B8:_%D0%94%D0%B6%D0%B0%D1%80%D0%B2%D0%B8%D1%81,_%D0%93%D1%80%D1%8D%D1%85%D0%B5%D0%BC,_%D0%AD%D0%BD%D0%B4%D1%80%D1%8E,_%D0%A7%D0%B5%D0%BD,_QuickHull&amp;diff=50782</id>
		<title>Статические выпуклые оболочки: Джарвис, Грэхем, Эндрю, Чен, QuickHull</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5_%D0%B2%D1%8B%D0%BF%D1%83%D0%BA%D0%BB%D1%8B%D0%B5_%D0%BE%D0%B1%D0%BE%D0%BB%D0%BE%D1%87%D0%BA%D0%B8:_%D0%94%D0%B6%D0%B0%D1%80%D0%B2%D0%B8%D1%81,_%D0%93%D1%80%D1%8D%D1%85%D0%B5%D0%BC,_%D0%AD%D0%BD%D0%B4%D1%80%D1%8E,_%D0%A7%D0%B5%D0%BD,_QuickHull&amp;diff=50782"/>
				<updated>2016-01-05T17:53:12Z</updated>
		
		<summary type="html">&lt;p&gt;176.114.249.43: /* Сложность */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
{{ready}}&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition=Выпуклой оболочкой множества точек называется пересечение всех выпуклых множеств, содержащих все заданные точки.}}&lt;br /&gt;
&lt;br /&gt;
Ниже приводятся основные алгоритмы построения выпуклых оболочек статического множества. Используются обозначения: &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; - размер входных данных, &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; - размер оболочки.&lt;br /&gt;
&lt;br /&gt;
= Алгоритм Джарвиса =&lt;br /&gt;
&lt;br /&gt;
По-другому &amp;quot;Gift wrapping algorithm&amp;quot; (Заворачивание подарка).&lt;br /&gt;
Он заключается в том, что мы ищем выпуклую оболочку последовательно, против часовой стрелки, начиная с определенной точки.&lt;br /&gt;
&lt;br /&gt;
== Описание Алгоритма ==&lt;br /&gt;
[[File:Graham1.png|thumb|250px|Промежуточный шаг алгоритма. Для точки &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt; ищем следующую перебором.]] &amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
# Возьмем точку &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; нашего множества с самой маленькой у-координатой (если таких несколько, берем самую правую из них). Добавляем ее в ответ.&lt;br /&gt;
# На каждом следующем шаге для последнего добавленного &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt; ищем &amp;lt;tex&amp;gt;p_{i + 1}&amp;lt;/tex&amp;gt; среди всех недобавленных точек и &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; {{Acronym|с максимальным полярным углом относительно &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt; (Если углы равны, надо сравнивать по расстоянию)|Считать углы не нужно, можно просто подставить в функцию сравнения предикат поворота}}. Добавляем &amp;lt;tex&amp;gt;p_{i + 1}&amp;lt;/tex&amp;gt; в ответ. Если &amp;lt;tex&amp;gt;p_{i + 1} == p_0&amp;lt;/tex&amp;gt; , заканчиваем алгоритм.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Корректность ==&lt;br /&gt;
&lt;br /&gt;
Точка &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt;, очевидно, принадлежит оболочке. На каждом последующем шаге алгоритма мы получаем прямую &amp;lt;tex&amp;gt;p_{i-1}p_i&amp;lt;/tex&amp;gt;, по построению которой все точки множества лежат слева от нее. Значит, выпуклая оболочка состоит из &amp;lt;tex&amp;gt;p_{i}&amp;lt;/tex&amp;gt;-ых и только из них.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
&lt;br /&gt;
Inplace-реализация алгоритма. &amp;lt;tex&amp;gt;S[1..n]&amp;lt;/tex&amp;gt; - исходное множество, &amp;lt;tex&amp;gt;n &amp;gt; 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  Jarvis(S)&lt;br /&gt;
    find i such that S[i] has the lowest y-coordinate and highest x-coordinate&lt;br /&gt;
    p0 = S[i]&lt;br /&gt;
    pi = p0&lt;br /&gt;
    k = 0&lt;br /&gt;
    do &lt;br /&gt;
      k++&lt;br /&gt;
      for i = k..n &lt;br /&gt;
        if S[i] has lower angle and higher distance than S[k] in relation to pi&lt;br /&gt;
          swap(S[i], S[k])&lt;br /&gt;
      pi = S[k]&lt;br /&gt;
    while pi != p0&lt;br /&gt;
    return k&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
&lt;br /&gt;
Добавление каждой точки в ответ занимает &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, всего точек будет &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, поэтому итоговая сложность &amp;lt;tex&amp;gt;O(nk)&amp;lt;/tex&amp;gt;. В худшем случае, когда оболочка состоит из всех точек сложность &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Gift_wrapping_algorithm Английская статья — Wikipedia]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%94%D0%B6%D0%B0%D1%80%D0%B2%D0%B8%D1%81%D0%B0 Русская статья — Wikipedia]&lt;br /&gt;
&lt;br /&gt;
= Алгоритм Грэхема =&lt;br /&gt;
&lt;br /&gt;
Алгоритм заключается в том, что мы ищем точки оболочки последовательно, используя стек. &lt;br /&gt;
&lt;br /&gt;
== Описание Алгоритма ==&lt;br /&gt;
&lt;br /&gt;
[[File:Graham2.png|thumb|400px|Промежуточный шаг алгоритма. Зелеными линиями обозначена текущая выпуклая оболочка, синими - промежуточные соединения точек, красными - те отрезки, которые раньше входили в оболочку, а сейчас нет. На текущем шаге при добавлении точки &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; последовательно убираем из оболочки точки с &amp;lt;tex&amp;gt;i+3&amp;lt;/tex&amp;gt;-ей до &amp;lt;tex&amp;gt;i+1&amp;lt;/tex&amp;gt;-ой]]&lt;br /&gt;
&lt;br /&gt;
# Находим точку &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; нашего множества с самой маленькой у-координатой (если таких несколько, берем самую правую из них), добавляем в ответ.&lt;br /&gt;
# Сортируем все остальные точки {{Acronym|по полярному углу относительно &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt;|Сортировка с компаратором 'Предикат поворота'}}.&lt;br /&gt;
# Добавляем в ответ &amp;lt;tex&amp;gt;p_1&amp;lt;/tex&amp;gt; - самую первую из отсортированных точек.&lt;br /&gt;
# Берем следующую по счету точку &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Пока &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; и две последних точки в текущей оболочке &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{i-1}&amp;lt;/tex&amp;gt; образуют неправый поворот (вектора &amp;lt;tex&amp;gt;p_i t&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_{i-1} p_i&amp;lt;/tex&amp;gt;), удаляем из оболочки &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Добавляем в оболочку &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Делаем п.5, пока не закончатся точки.&lt;br /&gt;
&lt;br /&gt;
== Корректность ==&lt;br /&gt;
&lt;br /&gt;
Докажем, что на каждом шаге множество &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt;-тых является выпуклой оболочкой всех уже рассмотренных точек. Доказательство проведем по индукции. &lt;br /&gt;
&lt;br /&gt;
* База. Для трех первых точек утверждение, очевидно, выполняется. &lt;br /&gt;
&lt;br /&gt;
* Переход. Пусть для &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; точек оболочки совпадают. Докажем, что и для &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; точек они совпадут.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим истинную оболочку &amp;lt;tex&amp;gt;ch(S \cup {i}) = ch(S) \cup i \setminus P&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; - множество всех точек из &amp;lt;tex&amp;gt;ch(S)&amp;lt;/tex&amp;gt;, видимых из &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;. Так как мы добавляли точки в нашу оболочку против часовой стрелки и так как &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-тая точка лежит в &amp;lt;tex&amp;gt;ch(S \cup i)&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;P&amp;lt;/tex&amp;gt; состоит из нескольких подряд идущих последних добавленных в оболочку точек, и именно их мы удаляем на текущем шаге. Поэтому наша оболочка и истинная для &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; точек совпадают.&lt;br /&gt;
&lt;br /&gt;
Тогда по индукции оболочки совпадают и для &amp;lt;tex&amp;gt;i = n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
&lt;br /&gt;
Inplace-реализация алгоритма. &amp;lt;tex&amp;gt;S[1..n]&amp;lt;/tex&amp;gt; - исходное множество, &amp;lt;tex&amp;gt;n &amp;gt; 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 Graham(S)&lt;br /&gt;
   find i such that S[i] has the lowest y-coordinate and highest x-coordinate&lt;br /&gt;
   swap(S[i], S[1])&lt;br /&gt;
   sort S[2..n] by angle in relation to S[1]&lt;br /&gt;
   k = 2&lt;br /&gt;
   for p = 3..n&lt;br /&gt;
     while S[k - 1], S[k], S[p] has non-right orientation&lt;br /&gt;
       k--&lt;br /&gt;
     swap(S[p], S[k + 1])   &lt;br /&gt;
   return k + 1&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
&lt;br /&gt;
Сортировка точек занимает &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; времени. При обходе каждая точка добавляется в ответ не более одного раза, поэтому сложность этой части - &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;. Суммарное время — &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Graham_scan Английская статья — Wikipedia]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%93%D1%80%D1%8D%D1%85%D0%B5%D0%BC%D0%B0 Русская статья — Wikipedia]&lt;br /&gt;
&lt;br /&gt;
= Алгоритм Эндрю =&lt;br /&gt;
&lt;br /&gt;
Алгоритм, очень похожий на алгоритм Грехема. Он заключается в том, что мы находим самую левую и самую правую точки, ищем для точек над и под этой прямой выпуклую оболочку Грехемом - {{Acronym|для них начальные точки будут лежать на &amp;lt;tex&amp;gt;\pm inf&amp;lt;/tex&amp;gt;, а сортировка по углу относительно далекой точки аналогична сортировке по координате|в этом легко убедиться, подставив в предикат поворота точку с 'бесконечно' координатой}}; после этого объединяем две оболочки в одну. &lt;br /&gt;
&lt;br /&gt;
== Описание Алгоритма ==&lt;br /&gt;
[[File:andrew1.png|thumb|400px|Промежуточный шаг алгоритма. Зелеными линиями обозначена текущая выпуклая оболочка, синими - промежуточные соединения точек, красными - те отрезки, которые раньше входили в оболочку, а сейчас нет. На текущем шаге при добавлении точки &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; последовательно убираем из оболочки точки с &amp;lt;tex&amp;gt;i+3&amp;lt;/tex&amp;gt;-ей до &amp;lt;tex&amp;gt;i+1&amp;lt;/tex&amp;gt;-ой]]&lt;br /&gt;
# Находим самую левую и самую правую точки множества - &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Делим множество на две части: точки над и под прямой.&lt;br /&gt;
# Для каждой половины ищем выпуклую оболочку Грехемом с условием, что сортируем не по полярному углу, а по координате.&lt;br /&gt;
# Сливаем получившиеся оболочки. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Корректность ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
См. доказательство алгоритма Грехема.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
&lt;br /&gt;
Inplace-реализация алгоритма. &amp;lt;tex&amp;gt;S[1..n]&amp;lt;/tex&amp;gt; - исходное множество, &amp;lt;tex&amp;gt;n &amp;gt; 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Andrew(S)&lt;br /&gt;
   sort S[1..n] by x-coordinate backward(than by y backward)&lt;br /&gt;
   k = 2&lt;br /&gt;
   for p = 3..n&lt;br /&gt;
    while S[k - 1], S[k], S[p] has non-right orientation&lt;br /&gt;
      k--&lt;br /&gt;
    swap(S[p], S[k + 1])&lt;br /&gt;
   k++   &lt;br /&gt;
   sort S[k + 1..n] by x-coordinate (than by y)&lt;br /&gt;
   for p = k + 1..n&lt;br /&gt;
     while S[k - 1], S[k], S[p] has non-right orientation&lt;br /&gt;
       k--&lt;br /&gt;
     swap(S[p], S[k + 1])&lt;br /&gt;
   return k + 1&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
&lt;br /&gt;
Сортировка точек занимает &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; времени. При обходе каждая точка добавляется в ответ не более одного раза, поэтому сложность двух обходов - &amp;lt;tex&amp;gt; 2 \cdot O(n)&amp;lt;/tex&amp;gt;. Суммарное время - &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;. Также можно отметить тот факт, что Эндрю в целом работает быстрее чем Грэхем, так как использует всего &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; поворотов, в то время как Грэхем использует &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; поворотов.&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Graham_scan#Notes Одно предложение о нем]&lt;br /&gt;
&lt;br /&gt;
= Алгоритм Чена =&lt;br /&gt;
&lt;br /&gt;
Является комбинацией двух алгоритмов - Джарвиса и Грехема. Недостатком Грэхема является необходимость сортировки всех точек по полярному углу, что занимает достаточно много времени &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt;. Джарвис требует перебора всех точек для каждой из &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; точек оболочки, что в худшем случае занимает &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Описание Алгоритма ==&lt;br /&gt;
&lt;br /&gt;
# Разобьем все множество на произвольные группы по &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; штук в каждой. Будем считать, что &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; нам известно. Тогда всего групп окажется &amp;lt;tex&amp;gt;r = n / m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Для каждой группы запускаем Грехема.&lt;br /&gt;
# Начиная с самой нижней точки ищем саму выпуклую оболочку Джарвисом, но перебираем не все точки, а по одной из каждой группы.&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
&lt;br /&gt;
На втором шаге алгоритма в каждой группе оболочка ищется за &amp;lt;tex&amp;gt;O(m \log m)&amp;lt;/tex&amp;gt;, общее время - &amp;lt;tex&amp;gt;O(r m \log m) = O(n \log m)&amp;lt;/tex&amp;gt;. На третьем шаге поиск каждой следующей точки в каждой группе занимает &amp;lt;tex&amp;gt;O(\log m)&amp;lt;/tex&amp;gt;, так как точки уже отсортированы, и мы можем найти нужную бинпоиском. Тогда поиск по всем группам займет &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(r \log m) = O(\frac{n}{m} \log m)&amp;lt;/tex&amp;gt;. Всего таких шагов будет &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, значит общее время - &amp;lt;tex dpi=&amp;quot;130&amp;quot;&amp;gt;O(\frac{kn}{m} \log m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Итоговое время - &amp;lt;tex&amp;gt;O(n (1 + \frac{k}{m}) \log m)&amp;lt;/tex&amp;gt;. Несложно видеть, что минимум достигается при &amp;lt;tex&amp;gt;m = k&amp;lt;/tex&amp;gt;. В таком случае сложность равна &amp;lt;tex&amp;gt;O(n \log k)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Поиск &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
Как заранее узнать &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;? Воспользуемся следующим методом. Положим &amp;lt;tex&amp;gt;m = 2^{2^t}&amp;lt;/tex&amp;gt;. Начиная с маленьких &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; будем запускать наш алгоритм, причем если на третьем шаге Джарвис уже сделал &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; шагов, то мы выбрали наше &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; слишком маленьким, будем увеличивать, пока не станет &amp;lt;tex&amp;gt;m \ge k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Тогда общее время алгоритма - &amp;lt;tex&amp;gt; \sum_{t=0}^{O(\log\log k)} O\left(n \log(2^{2^t})\right) = O(n) \sum_{t=0}^{O(\log\log k)} O(2^t) = O\left(n \cdot 2^{1+O(\log\log k)}\right) = O(n \log k).&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Chan%27s_algorithm Английская статья — Wikipedia]&lt;br /&gt;
* [http://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A7%D0%B0%D0%BD%D0%B0 Русская статья — Wikipedia]&lt;br /&gt;
&lt;br /&gt;
= Алгоритм QuickHull =&lt;br /&gt;
&lt;br /&gt;
== Описание Алгоритма ==&lt;br /&gt;
[[File:hull.png|thumb|250px|Промежуточный шаг алгоритма. Для прямой &amp;lt;tex&amp;gt;p_i p_1&amp;lt;/tex&amp;gt; нашли точку &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;. Над прямыми &amp;lt;tex&amp;gt;p_i p&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p p_1&amp;lt;/tex&amp;gt; точек нет, поэтому переходим к следующей прямой &amp;lt;tex&amp;gt;p_0 p_i&amp;lt;/tex&amp;gt;.]]&lt;br /&gt;
&lt;br /&gt;
# Найдем самую левую точку &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; и самую правую точку &amp;lt;tex&amp;gt;p_1&amp;lt;/tex&amp;gt; (Если таких несколько, выберем среди таких нижнюю и верхнюю соответственно).&lt;br /&gt;
# Возьмем все точки выше прямой &amp;lt;tex&amp;gt;p_0 p_1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Найдем среди этого множества точку &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt;, наиболее отдаленную от прямой (если таких несколько, взять самую правую).&lt;br /&gt;
# Рекурсивно повторить шаги 2-3 для прямых &amp;lt;tex&amp;gt;p_0 p_i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_i p_1&amp;lt;/tex&amp;gt;, пока есть точки.&lt;br /&gt;
# Добавить в ответ точки &amp;lt;tex&amp;gt;p_0 .. p_i .. p_1&amp;lt;/tex&amp;gt;, полученные в п. 3.&lt;br /&gt;
# Повторить пункты 2-5 для &amp;lt;tex&amp;gt;p_1 p_0&amp;lt;/tex&amp;gt; (то есть для &amp;quot;нижней&amp;quot; половины).&lt;br /&gt;
# Ответ - объединение списков из п. 5 для верхней и нижней половины.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Корректность ==&lt;br /&gt;
 &lt;br /&gt;
[[File:hull1.png|thumb|200px|]]&lt;br /&gt;
&lt;br /&gt;
Очевидно, что выпуклая оболочка всего множества является объединением выпуклых оболочек для верхнего и нижнего множества. Докажем, что алгоритм верно строит оболочку для верхнего множества, для нижнего рассуждения аналогичны.&lt;br /&gt;
Точки &amp;lt;tex&amp;gt;p_0&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_1&amp;lt;/tex&amp;gt; принадлежат оболочке.&lt;br /&gt;
&lt;br /&gt;
* Пусть какая-то точка входит в нашу оболочку, но не должна.&lt;br /&gt;
&lt;br /&gt;
Назовем эту точку &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. По алгоритму эта точка появилась как самая удаленная от некой прямой &amp;lt;tex&amp;gt;t_1 t_2&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; не входит в оболочку, то существует прямая &amp;lt;tex&amp;gt;t_3 t_4&amp;lt;/tex&amp;gt; из настоящей выпуклой оболочки, что &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; лежит снизу от прямой. Тогда какая-то из &amp;lt;tex&amp;gt;t_3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t_4&amp;lt;/tex&amp;gt; удалена от прямой дальше &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, что противоречит алгоритму.&lt;br /&gt;
&lt;br /&gt;
* Наоборот, пусть какой-то точки &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; в нашей оболочке нет, а должна быть.&lt;br /&gt;
&lt;br /&gt;
Пойдем вниз рекурсии в те ветки, где есть &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. В какой-то момент &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; окажется внутри некоторого треугольника. Но тогда возникает противоречие с тем, что &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; принадлежит выпуклой оболочке.&lt;br /&gt;
&lt;br /&gt;
Таким образом, наша оболочка совпадает с истинной, а значит алгоритм корректен.&lt;br /&gt;
&lt;br /&gt;
== Реализация ==&lt;br /&gt;
&lt;br /&gt;
Заметим, что длина высоты, опущенная из точки &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; на отрезок &amp;lt;tex&amp;gt;ab&amp;lt;/tex&amp;gt;, пропорциональна векторному произведению &amp;lt;tex&amp;gt;[bt \cdot ba]&amp;lt;/tex&amp;gt;, поэтому для сравнения можно использовать именно это.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
&lt;br /&gt;
Inplace-реализация алгоритма. &amp;lt;tex&amp;gt;S[1..n]&amp;lt;/tex&amp;gt; - исходное множество. &amp;lt;tex&amp;gt;quick\_hull()&amp;lt;/tex&amp;gt; - рекурсивная функция, находящая оболочку подмножества &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. В реализации в конце каждого подмножества находятся эл-ты, точно не принадлежащие оболочке.&lt;br /&gt;
&lt;br /&gt;
 QuickHull(S)&lt;br /&gt;
   find i such that S[i] has the highest x-coordinate and lowest y-coordinate &lt;br /&gt;
   swap(S[1], S[i])&lt;br /&gt;
   find i such that S[i] has the lowest x-coordinate and lowest y-coordinate&lt;br /&gt;
   swap(S[n], S[i])&lt;br /&gt;
   k = partition1(S) // разбиваем на те эл-ты, которые лежат над прямой и на остальные&lt;br /&gt;
   a = quick_hull(S, 1, k)&lt;br /&gt;
   b = quick_hull(S, k + 1, n);&lt;br /&gt;
   swap(S[a..k], S[k + 1, b])&lt;br /&gt;
   return start + (a - 1) + (b - k - 1) &amp;lt;br/&amp;gt;&lt;br /&gt;
 quick_hull(S, start, end)&lt;br /&gt;
   find i such that S[i], S[start], S[end] has maximum value&lt;br /&gt;
   (a, b) = partition2(S, start, end, S[i]) //свапаем эл-ты S так, чтобы сначала были все эл-ты над прямой S[start]S[i], потом S[i]S[end], потом все остальное&lt;br /&gt;
   c = quick_hull(S, start, a)&lt;br /&gt;
   d = quick_hull(S, a + 1, b)&lt;br /&gt;
   swap(S[c..a], S[a + 1..d])&lt;br /&gt;
   return start + (a - c) + (d - b)&lt;br /&gt;
&lt;br /&gt;
== Сложность ==&lt;br /&gt;
&lt;br /&gt;
Пусть время, необходимое для нахождения оболочки над некой прямой и множеством точек &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; есть &amp;lt;tex&amp;gt;T(S)&amp;lt;/tex&amp;gt;&lt;br /&gt;
Тогда &amp;lt;tex&amp;gt;T(S) = O(\|S\|) + T(A \in S) + T(B \in S)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;A, B&amp;lt;/tex&amp;gt; - множества над полученными прямыми. Отсюда видно, что в худшем случае, алгоритм тратит &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt;. На рандомных же данных это число равно &amp;lt;tex&amp;gt;O(n \log n)&amp;lt;/tex&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [http://en.wikipedia.org/wiki/QuickHull Английская статья — Wikipedia]&lt;/div&gt;</summary>
		<author><name>176.114.249.43</name></author>	</entry>

	</feed>