Вычислительная геометрия

Пересечения отрезков

OpenStreetMap хранит 800 миллионов узлов и 70 миллионов дорог. Каждый раз, когда приложение строит маршрут через город, ему нужно знать где дороги пересекаются с реками, зонами и границами. Наивный O(n^2) на 70 миллионах отрезков - 5*10^15 операций. Sweep line доводит это до секунд.

  • **ГИС:** наложение слоёв карты - найти где дороги пересекают реки, границы зон, трубопроводы
  • **Collision detection в играх:** broad phase - sweep and prune для AABB, определяет потенциальные столкновения среди тысяч объектов
  • **САПР/PCB design:** проверка пересечений дорожек на печатной плате - критически важна для производства

Shamos, Hoey, Bentley, Ottmann - sweep революция

В 1976 году Шамос и Хой представили первый sweep line алгоритм для проверки наличия пересечений - O(n log n). Это был прорыв: до них задача казалась неизбежно O(n^2). В 1979 Бентли и Оттманн расширили идею до нахождения ВСЕХ k пересечений за O((n+k) log n). Статья 1979 года стала классикой: алгоритм появился в каждом учебнике по вычислительной геометрии и лёг в основу CGAL - промышленной библиотеки, которой пользуются Google Maps и AutoCAD.

Предварительные знания

  • Convex Hull

Парадигма Sweep Line

Вертикальная линейка движется слева направо по плоскости. В каждый момент она «видит» только отрезки, которые её пересекают. По мере движения отрезки появляются и исчезают. Это **sweep line** - одна из мощнейших парадигм вычислительной геометрии. Задача 2D становится серией задач 1D.

**Sweep Line** - парадигма, где вертикальная линия движется по плоскости слева направо. Два ключевых компонента: **Event Queue** (очередь событий - точки, где что-то меняется) и **Status Structure** (упорядоченное множество отрезков, пересекающих sweep line в данный момент).

Три типа событий при sweep line для отрезков:

Тип событияКогдаДействие
Left endpointSweep line достигает левого конца отрезкаВставить в status, проверить соседей
Right endpointSweep line достигает правого концаУдалить из status, проверить новых соседей
IntersectionДва отрезка пересекаютсяПоменять порядок в status, проверить новых соседей

Ключевое наблюдение: **два отрезка могут пересечься только если они соседи в status structure**. Не нужно проверять все пары - достаточно проверять соседей при каждом изменении status. Это и даёт выигрыш в сложности.

Почему в sweep line алгоритме проверяются только соседние отрезки в status structure?

Алгоритм Bentley-Ottmann

Bentley и Ottmann в 1979 году превратили идею sweep line в конкретный алгоритм для нахождения **всех** пересечений среди n отрезков. Наивный подход - O(n^2) пар. Bentley-Ottmann - O((n + k) log n), где k - число пересечений. Разница при n = 10 000 с k = 50: наивный 10^8, B-O около 10^5.

**Bentley-Ottmann** находит все k пересечений среди n отрезков за O((n + k) log n) времени и O(n + k) памяти. Event Queue - heap, Status Structure - сбалансированное BST. На каждое событие - O(log n) операций.

АлгоритмВремяПамятьКогда использовать
Наивный (все пары)O(n^2)O(1)n < 100
Bentley-OttmannO((n+k) log n)O(n+k)Общий случай
Balaban (1995)O(n log n + k)O(n+k)Теоретически оптимален
Shamos-HoeyO(n log n)O(n)Только ЕСТЬ ли пересечение (да/нет)

**Сложности реализации:** вырожденные случаи - три отрезка, пересекающиеся в одной точке; вертикальные отрезки; пересечение в концевой точке. Production-реализации (CGAL, Shapely) обрабатывают все эти случаи.

Для 1000 отрезков с 50 пересечениями, Bentley-Ottmann работает за:

Red-Blue Intersections

Отрезки разделены на два набора - «красные» и «синие». Нас интересуют только пересечения **между** наборами, но не внутри каждого. Это задача **red-blue intersections** - возникает при наложении карт, collision detection между группами объектов, операциях с полигонами в GIS.

**Red-Blue Intersections:** даны два множества отрезков R (красные, n штук) и B (синие, m штук). Найти все пересечения r ∩ b, где r ∈ R, b ∈ B. Пересечения внутри R и внутри B - игнорируем.

Для задачи red-blue пересечений существуют и специализированные алгоритмы. Если один набор - горизонтальные отрезки, а другой - вертикальные, задача решается за O(n log n + k) с помощью **segment tree** или **interval tree**.

Вариант задачиСложностьМетод
Общие red-blue отрезкиO((n+m+k) log(n+m))Модифицированный Bentley-Ottmann
Горизонтальные × вертикальныеO((n+m) log(n+m) + k)Sweep line + segment tree
Красные - отрезки, синие - точкиO((n+m) log n)Sweep + binary search
Прямоугольники × точкиO((n+m) log n + k)Sweep + interval tree

В задаче red-blue intersections, зачем игнорировать пересечения внутри одного цвета?

Output-Sensitive алгоритмы

В задачах вычислительной геометрии размер вывода **сильно варьируется**. У n отрезков может быть 0 пересечений или O(n^2). Алгоритм, чья сложность зависит от размера вывода - **output-sensitive**. Зачем тратить O(n^2), если пересечений всего 3?

**Output-sensitive алгоритм** - алгоритм, сложность которого зависит не только от размера входа n, но и от размера вывода k. Для задачи пересечения отрезков оптимум - O(n log n + k), достигнутый алгоритмом Балабана (1995).

Bentley-Ottmann в **худшем** случае (k = O(n^2)) медленнее наивного из-за log-фактора! Теоретически оптимальный алгоритм Балабана не имеет этой проблемы, но значительно сложнее в реализации.

ЗадачаЛучший алгоритмOutput-sensitive?
Есть ли пересечение? (boolean)O(n log n) Shamos-HoeyНет (k не влияет)
Найти все k пересеченийO(n log n + k) BalabanДа
Подсчитать k (не перечисляя)O(n^(4/3) log n)Частично
Convex hull (h вершин)O(n log h) ChanДа

Sweep line - выразительная парадигма, превращающая 2D-задачу в серию 1D-событий. Bentley-Ottmann - практичная реализация для пересечения отрезков. Output-sensitivity - важный принцип: алгоритм не должен тратить O(n^2), если ответ содержит O(1) элементов.

Наивный алгоритм O(n^2) для пересечения всех пар отрезков достаточен для практических задач

Для тысяч отрезков (карты, CAD, collision detection) O(n^2) неприемлем. Bentley-Ottmann за O((n+k) log n) на порядки быстрее при малом k. А для boolean-проверки Shamos-Hoey - O(n log n) без зависимости от k

В реальных приложениях n может быть 10^5-10^6 (дорожная сеть, полигоны карты). O(n^2) = 10^10-10^12 - непрактично. Sweep line сводит задачу к O(n log n + k), что на практике часто почти линейно.

Для n = 10000 отрезков без единого пересечения (k = 0), какой подход оптимален?

Ключевые идеи

  • **Sweep line** - парадигма: вертикальная линия движется по плоскости, обрабатывая события (endpoints, intersections)
  • **Bentley-Ottmann** O((n+k) log n): event queue + status BST. Проверяем только соседей в status
  • **Red-Blue Intersections:** находим пересечения только между двумя группами - модифицированный sweep line
  • **Output-sensitivity:** O(n log n + k) - честная оценка, не штрафующая за малое число пересечений

Связанные темы

Sweep line - универсальная парадигма, применяемая далеко за пределами пересечения отрезков:

  • Точки, отрезки, полигоны — Базовые примитивы: cross product и orientation - основа проверки пересечения пар
  • Выпуклая оболочка — Graham Scan - тоже «обход по порядку». Output-sensitivity: Chan's O(n log h) vs Graham O(n log n)
  • Сбалансированные деревья — Status structure - BST. Эффективность sweep line зависит от O(log n) операций в BST

Вопросы для размышления

  • Sweep line двигается слева направо. Что меняется, если все отрезки вертикальные? Как адаптировать алгоритм?
  • Bentley-Ottmann хуже наивного при k = O(n^2). Почему на практике это редко проблема?
  • Как применить sweep line для задачи: найти все пары прямоугольников, которые пересекаются?

Связанные уроки

  • cgeom-01 — Cross product и orientation - фундамент проверки пары отрезков
  • cgeom-02 — Graham Scan - тоже sweep-идея, output-sensitivity: Chan O(n log h)
  • alg-05 — Сбалансированные BST - основа status structure в Bentley-Ottmann
  • cgeom-04 — Диаграмма Вороного строится через Fortune sweep line
  • cgeom-05 — Триангуляция Делоне использует sweep для построения
  • alg-07 — Interval trees - альтернатива sweep для прямоугольных запросов
  • la-04-lines-planes
Пересечения отрезков

0

1

Войти