Блог пользователя Edvard

Автор Edvard, 12 лет назад, перевод, По-русски

Всем привет!

Сегодня на этапе открытого кубка была задача с добавлением точки в выпуклую оболочку. Эта задача просто решается если уметь быстро строить касательные к выпуклому многоугольнику. Я слышал, что вроде такой алгоритм есть. Кто-нибудь знает где почитать можно или как он примерно работает?

UPD: Спасибо за ответы

  • Проголосовать: нравится
  • +14
  • Проголосовать: не нравится

»
12 лет назад, # |
  Проголосовать: нравится +17 Проголосовать: не нравится

Мы решали онлайн за лог: взяли точку внутри многоугольника, нашли бинпоиском, в каком угле между вершинами лежит точка-запрос, её центральная симметрия и сделали два бинпоиска (по углу между стороной и отрезком, соединяющим запрос и конец отрезка) с каждой из сторон, нашли каждую из касательных.

»
12 лет назад, # |
  Проголосовать: нравится +4 Проголосовать: не нравится

Примерно можно делать так: поддерживать в сете все точки выпуклой оболочки отсортированные по углу, идея в том что касательные будут искаться c помощью lower_bound.

»
12 лет назад, # |
  Проголосовать: нравится +22 Проголосовать: не нравится

Ну мы придумали следующие, правда допихал я это только сейчас, из-за кривизны рук(
Пусть у нас уже есть выпуклая оболочка точек и точка p для которой надо построить две касательные, левую и правую. Во-первых проверим, что эта точка лежит снаружи. Ну это известный алгоритм за лог н. Кроме того, если точка таки лежит снаружи, этот алгоритм даст нам ребро многоугольника, точно видимое из этой точки, запомним любую вершину этого ребра и назовём её начальным приближением. Если наша точка лежит левее самой левой точки многоугольники, то тогда начальным приближением будет эта самая левая точка. Теперь когда знаем начальное приближение можно найти, к примеру, левую касательную используя бинарный поиск. Пусть в многоугольнике n вершин, они находятся в массиве P, а наше начальное приближение имеет индекс st в этом массиве. Тогда левая граница БП l = 1, правая r= n-1, и текущая точка, которую будем тестировать на "видимость" из нашей будет иметь индекс P[(st — (l+r)/2 + n)%n]. Осталось проверить, что эта точка, назовём её curr, является видимой и лежит левее точки P[st]. Если вектора (curr — p) и (P[st] — p) образуют левый поворот, то curr точно не видима, или видима но правее st, т.е. в любом случаи нам не подходит. Иначе, если вектора (next — curr) и (P[st]-curr) образуют левый поворот, то curr опять же не видна. Иначе она видна. Здесь next точка следующая в нашем массиве за точкой curr. В итоге получим индекс левой точки касания, с правой аналогично.