Выпуклый корпус, состоящий из макс. n баллов

Учитывая набор 2D-точек X, я хотел бы найти выпуклую оболочку, состоящую из максимальных n точек. Конечно, это не всегда возможно. Поэтому я ищу приблизительную выпуклую оболочку, состоящую из макс. n точек, максимально покрывающих множество точек X.

Говоря более формально, если F(H,X) возвращает количество точек X, покрываемых выпуклой оболочкой H, где |H| количество точек, из которых построен корпус, то я ищу следующее количество:

H_hat = argmax_H F(H,X), s.t |H|<=n

Другим способом решения задачи является задача нахождения полигона, состоящего из макс. n углов множества X так, чтобы оно максимально покрывало указанное множество X.

Я придумал следующее:

X = getSet() \\ Get the set of 2D points
H = convexHull(X) \\ Compute the convex hull
while |H| > n do
    n_max = 0
    for h in H:
        H_ = remove(h,H) \\ Remove one point of the convex hull
        n_c = computeCoverage(X,H_) \\ Compute the coverage of the modified convex hull.
        \\ Save which point can be removed such that the coverage is reduced minimally.
        if n_c > n_max:
            n_max = n_c
            h_toremove = h
    \\ Remove the point and recompute the convex hull.
    X = remove(h,X)
    H = convexHull(X)

Однако это очень медленный способ сделать это. У меня большой набор точек, а n (ограничение) маленькое. Это означает, что исходная выпуклая оболочка содержит много точек, поэтому цикл while выполняется очень долго. Есть ли более эффективный способ сделать это? Или есть другие предложения по приближенным решениям?

Должен ли H_hat состоять из исходных точек или можно добавить новые?

kafman 08.02.2019 13:50

Эй, я добавил вычислительную геометрию в качестве тега, так как знаю по крайней мере одного эксперта, который специально ей следует. Вы проделали отличную работу с тегами, поэтому мне пришлось исключить слово «выпуклый». Надеюсь, что все в порядке; вы можете внести коррективы по желанию.

David Eisenstat 08.02.2019 15:41

Основная трудность заключается в том, что размер корпуса не уменьшается монотонно при удалении точек.

Yves Daoust 08.02.2019 16:10

Сомневаюсь, что оптимальное решение можно найти постепенно. Представьте случай H=3 и предположим, что вы нашли треугольник, покрывающий 5 точек. Может быть, есть еще один в совершенно другом месте, вмещающий 100 из них.

Yves Daoust 08.02.2019 16:15

@YvesDaoust Возможно, вы правы, но единственные точные решения, которые я могу придумать, намного медленнее, чем предложение в вопросе.

David Eisenstat 08.02.2019 16:17

@DavidEisenstat: я имею в виду, что проблема, похоже, не имеет хороших локальных свойств. Изменение одной вершины может изменить 90% покрытия.

Yves Daoust 08.02.2019 16:21

@YvesDaoust, весьма вероятно, что написанный мной алгоритм не вычисляет оптимальное решение. Это лучшее, что я придумал, думая об этом. Теперь я рассмотрю идеи ниже.

spurra 08.02.2019 16:23

@DavidEisenstat Спасибо за настройку тегов.

spurra 08.02.2019 16:25

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

Yves Daoust 08.02.2019 16:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
9
1 099
3

Ответы 3

Возможно, вам подойдет следующий подход: сначала вычислите выпуклую оболочку H. Затем выберите подмножество точек n случайным образом из H, который строит новый многоугольник, который может не покрывать все точки, поэтому назовем его квазивыпуклой оболочкой Q. Подсчитайте, сколько точек содержится в Q (инлайнеры). Повторите это определенное количество раз и оставьте предложение Q с наибольшим количеством вставок.

Это кажется немного связанным с RANSAC, но для этой задачи у нас нет представления о том, что такое выброс, поэтому мы не можем реально оценить коэффициент выбросов. Следовательно, я не знаю, насколько хорошим будет приближение или сколько итераций вам нужно, чтобы получить разумный результат. Может быть, вы можете добавить некоторые эвристики вместо того, чтобы выбирать точки n чисто случайным образом, или вы можете установить пороговое значение того, сколько точек должно по крайней мере содержаться в Q, а затем остановиться, когда вы достигнете этого порога.

Редактировать

На самом деле, подумав об этом, вы могли бы использовать подход RANSAC:

max_inliers = 0
best_Q = None
while(true):
    points = sample_n_points(X)
    Q = construct_convex_hull(points)
    n_inliers = count_inliers(Q, X)
    if n_inliers > max_inliers:
        max_inliers = n_inliers
        best_Q = Q
    if some_condition:
        break

Преимущество этого заключается в том, что создание выпуклой оболочки происходит быстрее, чем в вашем подходе, так как он использует максимум точек n. Кроме того, проверка количества вставок должна быть быстрой, поскольку это может быть просто набор сравнений знаков с каждой стороной выпуклой оболочки.

Пара идей.

  1. Точки, которые мы исключаем при удалении вершины, лежат в треугольнике, образованном этой вершиной и двумя смежными с ней вершинами на выпуклой оболочке. Удаление любой другой вершины не влияет на набор потенциально исключаемых точек. Таким образом, нам нужно всего лишь дважды пересчитать покрытие для каждой удаленной вершины.

  2. Говоря о пересчете покрытия, мы не обязательно должны рассматривать каждую точку. Эта идея не улучшает худший случай, но я думаю, что на практике это должно быть большим улучшением. Поддерживайте индекс точек следующим образом. Выберите случайную вершину, которая будет «корнем», и сгруппируйте точки, по которым треугольник, образованный корнем, и две другие вершины содержат их (время O (m log m) с хорошим алгоритмом). Всякий раз, когда мы удаляем некорневую вершину, мы объединяем и фильтруем два набора точек для треугольников, включающих удаленную вершину. Всякий раз, когда мы пересчитываем покрытие, мы можем сканировать только точки в двух соответствующих треугольниках. Если мы когда-нибудь удалим этот корень, выберем новый и переделаем индекс. Общая стоимость этого обслуживания составит O(m log^2 m) в ожидании, где m — количество баллов. Однако оценить стоимость вычислительного покрытия сложнее.

  3. Если точки достаточно равномерно распределены внутри корпуса, можно использовать площадь в качестве прокси для покрытия. Сохраните вершины в очереди приоритетов, упорядоченной по площади их треугольника, образованного их соседями (ухом). Всякий раз, когда мы удаляем точку, обновляем область уха двух ее соседей. Это алгоритм O (m log m).

Следующее не решает вопрос в том виде, в каком я его сформулировал, но решает проблему, породившую вопрос. Поэтому я хотел добавить его на случай, если кто-то еще столкнется с чем-то подобным.

Я исследовал два подхода:

1) Рассматривает выпуклую оболочку как многоугольник и применяет к ней алгоритм упрощения многоугольника. Конкретным алгоритмом, который я исследовал, был Алгоритм Рамера-Дугласа-Пекера.

2) Применить алгоритм, описанный в вопросе, без пересчета выпуклой оболочки.

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

Другие вопросы по теме