Размышляя над одной проблемой, я понял, что мне нужно создать эффективный алгоритм, решающий следующую задачу:
Проблема: нам дан двумерный квадратный прямоугольник со стороной , стороны которого параллельны осям. Мы можем посмотреть на это через верх. Тем не менее, есть также горизонтальных сегментов. Каждый сегмент имеет целочисленную координату ( ) и координаты ( ) и соединяет точки и (посмотрите на картинка ниже).
Мы хотели бы знать, для каждого сегмента блока в верхней части блока, насколько глубоко мы можем смотреть вертикально внутрь блока, если просмотрим этот сегмент.
Пример: с учетом и m = 7 сегментов, расположенных, как на рисунке ниже, получается результат (5, 5, 5, 3, 8, 3, 7, 8, 7) . Посмотрите, как глубокий свет может попасть в коробку.
К счастью для нас, как и является достаточно малы , и мы можем сделать вычисление офф-лайн.
Самым простым алгоритмом, решающим эту проблему, является перебор: для каждого сегмента пересекайте весь массив и обновляйте его при необходимости. Однако это дает нам не очень впечатляющий .
Значительным улучшением является использование дерева сегментов, которое способно максимизировать значения в сегменте во время запроса и считывать окончательные значения. Я не буду описывать это дальше, но мы видим, что временная сложность составляет .
Однако я придумал более быстрый алгоритм:
Контур:
Сортируйте сегменты в порядке убывания -координаты (линейное время, используя вариацию сортировки отсчета). Теперь обратите внимание, что если какой-либо сегмент единицы ранее был покрыт каким-либо сегментом, то ни один следующий сегмент больше не может ограничивать луч света, проходящий через этот сегмент единицы. Затем мы сделаем разметку линии сверху донизу коробки.х х
Теперь давайте введем несколько определений: сегмент единицы - это воображаемый горизонтальный сегмент на развертке, координаты которого являются целыми числами и длина которого равна 1. Каждый сегмент в процессе развертки может быть либо без опознавательных знаков (то есть луч света, идущий от верх коробки может доходить до этого сегмента) или отмечен (противоположный случай). Рассмотрим единичный сегмент с , всегда без опознавательных знаков. Давайте также введем множества . Каждый набор будет содержать целую последовательность последовательных отмеченных сегментов единиц (если они есть) с последующей неотмеченнойx x x 1 = n x 2 = n + 1 S 0 = { 0 } , S 1 = { 1 } , … , S n = { n } x сегмент.
Нам нужна структура данных, которая способна эффективно работать с этими сегментами и устанавливает их. Мы будем использовать структуру find-union, расширенную полем, содержащим максимальный индекс сегмента unit (индекс немаркированного сегмента).
Теперь мы можем эффективно обрабатывать сегменты. Допустим, мы сейчас рассматриваем сегмент по порядку (назовем его «запрос»), который начинается в и заканчивается в . Нам нужно найти все немаркированные сегменты блока, которые содержатся внутри сегмента (это именно те сегменты, на которых луч света закончит свой путь). Мы сделаем следующее: во-первых, мы найдем первый немаркированный сегмент внутри запроса ( найдите представителя набора, в котором содержится и получите максимальный индекс этого набора, который по определению является немаркированным сегментом ). Тогда этот индексx 1 x 2 x i x 1 x y x x + 1 x ≥ x 2 находится внутри запроса, добавьте его к результату (результат для этого сегмента - ) и отметьте этот индекс ( объединение наборов, содержащих и ). Затем повторяйте эту процедуру, пока мы не найдем все неотмеченные сегменты, то есть следующий запрос Find даст нам индекс .
Обратите внимание, что каждая операция find-union будет выполняться только в двух случаях: либо мы начинаем рассматривать сегмент (что может произойти раз), либо мы просто пометили сегмент unit (это может произойти раз). Таким образом, общая сложность равна ( - обратная функция Аккермана ). Если что-то не понятно, я могу подробнее остановиться на этом. Может быть, я смогу добавить несколько фотографий, если у меня будет время.x n O ( ( n + m ) α ( n ) ) α
Теперь я достиг "стены". Я не могу придумать линейный алгоритм, хотя кажется, что он должен быть. Итак, у меня есть два вопроса:
- Существует ли алгоритм линейного времени (то есть ), решающий проблему видимости горизонтального сегмента?
- Если нет, что является доказательством того, что проблема видимости ?