Точка в многоугольнике

Я пытаюсь решить проблему с SPOJ, это https://www.spoj.pl/problems/FSHEEP/

Нам нужно выяснить, находится ли точка внутри многоугольника. Как видим, это не выпуклый многоугольник (изображение из задачи).

Я пытался решить это за O (n * m) время с помощью алгоритма Ray Casting, описанного в Википедии или на любом другом сайте.

Но как решить это за O (n log m)? Другими словами, как проверить, находится ли точка в многоугольнике в логарифмическом времени?

Ваше здоровье


person Krzysztof Lewko    schedule 23.05.2011    source источник


Ответы (1)


Так как это задача, напоминающая домашнее задание, я дам вам помощь в виде домашнего задания.

Практическое правило: всякий раз, когда вы видите log n, вы должны думать «что-то двоичное» (поиск, дерево и т. Д.). Когда вы видите n log n, вы должны подумать «сортировать». Вы будете удивлены, как часто это срабатывает. Можете ли вы отсортировать вершины и выполнить бинарный поиск по ним в рамках ограничений большого O?

ОБНОВИТЬ:

Я не хотел портить вам удовольствие: на самом деле вам даны вершины многоугольника в отсортированном порядке, поэтому важная сортировка была сделана за вас. Вам не нужно делать интервал в угловом пространстве, используйте индексы отсортированного массива вершин в качестве интервала.

Направьте свой луч от фермера к вершине. Если по часовой стрелке, двоичный поиск по часовой стрелке. Если он повернут против часовой стрелки, выполняется двоичный поиск в этом направлении. Две вершины и фермер образуют ограничивающий треугольник. Овца находится в ограничивающем треугольнике?

Безумный ленивый псевдокод:

if vertex[m] and vertex[0] trivially bound the sheep
  l=m, r=0
else
  l=0, r=m
  while (r-l > 1)
    middle = (r-l)/2
    if vertex[l] and vertex[middle] bound sheep
       r = middle
       continue
    else if vertex[middle] and vertex[r] bound sheep
       l = middle
       continue
    else some_jerk_gave_you_a_sheep_on_a_ray

check vertex[l],vertex[r],farmer triangle

Двоичный поиск - O (log m). Проверка треугольника - O (1). Итерация по n овцам дает O (n) * O (log m) * O (1) = O (n log m).

person ccoakley    schedule 23.05.2011
comment
Привет, спасибо за ответ. Это не моя домашняя работа, просто хобби. А не могли бы вы разработать этот метод двоичного поиска? Я читал, что нам нужно делать интервалы и искать нашу точку зрения, но я не мог найти, насколько велики интервалы и что дальше? :) - person Krzysztof Lewko; 23.05.2011
comment
Не знаю, правильно ли я понял: let s - начальная вершина let l - последняя вершина mid = (s + l) / 2, поэтому t [mid-1] t [mid] t [mid + 1] образует треугольник, если точка находится в треугольнике: она в многоугольнике, если точка имеет нижние координаты (x (?) и y (?)), продолжать поиск в l = s; s = s; если выше - наоборот. Я правильно понял? Спасибо за прекрасную идею. - person Krzysztof Lewko; 24.05.2011
comment
Извини, нет. Сначала выполните двоичный поиск, пока у вас не будет двух соседних вершин, так что луч от фермера до вершины a находится слева от овцы, а луч от фермера до вершины b - справа от овцы. На самом деле вы можете просто использовать фермера, a, b как ограничивающий треугольник (не обращайте внимания на клин, обращенный к вам, в этом нет необходимости). В остальном ты понял. - person ccoakley; 24.05.2011
comment
Очень полное и красивое объяснение! Спасибо за это получил :) - person Krzysztof Lewko; 24.05.2011
comment
В конце концов я доберусь туда :) Спасибо за терпение. - person ccoakley; 24.05.2011
comment
Будьте осторожны с единичными ошибками. В моем псевдокоде в качестве индексов используются как 0, так и m. На практике это, вероятно, 0 и m-1. Наконец, коллинейный случай сложнее, чем я предполагал. Поскольку вы, возможно, используете числа с плавающей запятой, вы должны знать, что иногда из-за неточности вы можете получить точку, которая находится как справа, так и слева от строки (или ни одной из них). Оба являются типичными тестами на коллинеарность. Обычно это преподносится в учебниках по вычислительной геометрии как ошибка. Возможно, тебе сейчас все равно. Просто знайте, что это случается. - person ccoakley; 24.05.2011
comment
Для проверки колинеарности мы можем использовать кросс-произведение, не так ли? - person Krzysztof Lewko; 24.05.2011
comment
Зависит от того, насколько малы вы готовы принять эпсилон, отличный от нуля. Помните, что, поскольку числа с плавающей запятой не являются точными, их умножение и добавление по-разному может дать разные результаты даже для математически эквивалентных операторов. Поиск в Google по теме "Надежность в вычислительной геометрии" может предоставить вам богатый источник примеров. - person ccoakley; 24.05.2011