Мне нужно оптимально решить следующую проблему.
Входные данные:
- N точек на плоскости, заданной как (x, y) пара целочисленных координат
- M точек в той же плоскости, заданных как (x, y) пара целочисленных координат, представляющих центр круга. Все эти круги имеют (0, 0) на своих краях.
Мне нужно найти способ выделить несколько кругов, обладающих свойством, чем для любого «хорошего» круга, ни одна точка из первых N точек не лежит в выбранном круге или на краю выбранного круга.
Количество точек и кружков составляет порядка 100 000. Очевидное решение проверки каждого круга с каждой точкой имеет сложность O (N * M), и при 100 000 кругов и 100 000 точек на Core 2 Duo с 64-битным кодом SSE3 одинарной точности требуется около 15 секунд. Эталонная реализация, с которой я конкурирую, занимает всего около 0,1 секунды с теми же данными. Я знаю, что эталонная реализация O (Nlog N + Mlog M).
Я думал об оптимизации моего алгоритма следующим образом. Сделайте 2 копии данных точек и отсортируйте копии по координате x, соответственно по координате y. Затем используйте только точки, которые лежат в квадрате, определенном как [(xc - r, yc - r); (xc + r, yc + r)], где (xc, yc) - центр «текущего» круга с радиусом r. Я могу найти точки в этом интервале, используя бинарный поиск, потому что теперь я работаю с отсортированными данными. Сложность этого подхода должна быть O (Nlog N + Mlog ^ 2 N), и, действительно, он быстрее, но все же значительно медленнее, чем эталонный.
Я более или менее знаю, как работает эталонная реализация, но есть некоторые шаги, которые я не понимаю. Я попытаюсь объяснить, что я знаю до сих пор:
Радиус круга с координатами (Xc, Yc):
- Rc = sqrt (Xc * Xc + Yc * Yc) (1)
Это потому, что (0, 0) находится на краю круга.
Чтобы точка P (x, y) находилась за пределами круга, должно выполняться следующее неравенство:
- sqrt ((Xc - x) ^ 2 + (Yc - y) ^ 2)> Rc (2)
Теперь, если мы подставим Rc из (1) в (2), возведем в квадрат неравенство после того, как сделаем несколько простых вычислений:
- Yc <1 / 2y * (x ^ 2 + y ^ 2) - Xc * x / y (3.1) для y> 0
- Yc> 1 / 2y * (x ^ 2 + y ^ 2) - Xc * x / y (3.2) для y <0 </li>
(3.1) и (3.2) должны быть истинными для данного круга C (Xc, Yc) для любого (x, y), выбранного из входных данных.
Для простоты давайте сделаем несколько обозначений:
- A (x, y) = 1 / 2y * (x ^ 2 + y ^ 2) (4.1)
- B (x, y) = -x / y (4,2)
- E (Xc) = 1 / 2y * (x ^ 2 + y ^ 2) - Xc * x / y = A (x, y) + Xc * B (x, y) (4,3)
Мы можем видеть, что для данного круга C (Xc, Yc) мы можем написать (3) как:
- Yc 0
- Yc> MAX (E (Xc)) (5.2) для всех точек с y <0 </li>
Мы можем видеть, что E (Xc) является линейной функцией относительно Xc с 2 параметрами - A (x, y) и B (x, y). Это означает, что в основном E (Xc) представляет в евклидовом пространстве семейство линий с 2 параметрами.
Теперь вот часть, которую я не понимаю. Они говорят, что из-за свойства, указанного в предыдущем параграфе, мы можем вычислить MIN () и MAX () в O (1) амортизированном времени вместо O (N), используя алгоритм Envelope. Я не знаю, как может работать алгоритм конвертов.
Любые советы о том, как реализовать алгоритм Envelope?
Заранее спасибо!
Edit:
Вопрос не в том, что такое конверт в математическом смысле - я это уже знаю. Вопрос состоит в том, как определить огибающую за лучшее время, чем O (n), по-видимому, это можно сделать в амортизированной форме O (1).
У меня есть семейство функций, мне нужно вычислить огибающую, и у меня есть массив всех возможных параметров. Как оптимально решить задачу максимизации?
Еще раз спасибо!