Выпуклая оболочка минимального периметра подмножества набора точек

учитывая n точек на плоскости. 3 не лежат на одной прямой.

учитывая число k.

найти подмножество K точек, так что выпуклая оболочка K точек имеет минимальный периметр из любой выпуклой оболочки подмножества k точек.

Я могу думать о наивном методе, выполняемом в O (n^k K log k). (Найдите выпуклую оболочку каждого подмножества размера k и выведите минимум).

Я думаю, что это проблема NP, но я не могу найти ничего подходящего для сокращения к.

у кого есть идеи по этой проблеме?

пример

the set of n=4 points {(0,0), (0,1), (1,0), (2,2)} and k=3

результат:

{(0,0),(0,1),(1,0)}

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

4 ответов


Это можно сделать в O(kn^3) времени и o (kn^2) пространстве(или, возможно, O (kn^3), Если вы хотите фактические точки).

эта бумага:http://www.win.tue.nl / ~gwoegi / документы / area-k-gons.pdf

по Eppstein et al, имеет алгоритмы для решения этой проблемы для минимального периметра и других весовых функций, таких как площадь, сумма внутренних углов и т. д., которые следуют определенным ограничениям, хотя название говорит о минимальной площади (см. следствие 5.3 для периметра).

в основная идея динамического программирования заключается в следующем (прочитайте первые несколько абзацев раздела 4):

предположим, что S-заданное множество точек, а Q-выпуклая оболочка K точек с минимальным периметром.

пусть p1-самая нижняя точка Q, p2 и p3-следующие точки На корпусе в порядке против часовой стрелки.

мы можем разложить Q на треугольник p1p2p3 и выпуклую оболочку из K-1 точек Q' (которая разделяет сторону p1p3 с треугольником p1p2p3).

основное наблюдение заключается в том, что Q' является оптимальным для k-1, в котором самая нижняя точка-p1, а следующая точка-p3, и все точки Q' лежат на одной стороне линии p2 - >p3.

таким образом, поддерживая 4D массив оптимальных многоугольников для каждого квадруполя (pi, pj, pk, m) такой, что

  • многоугольник является выпуклой оболочкой ровно m точек S.
  • pi-самая нижняя точка многоугольника.
  • pj является следующая вершина в порядке против часовой стрелки,
  • все точки многоугольника лежат слева от линии pi - > pj.
  • все точки лежат на той же стороне pj->pk, что и pi.

может помочь нам найти оптимальные многоугольники для m=k, учитывая оптимальные многоугольники для m

в статье точно описывается, как это сделать, чтобы достичь заявленных границ пространства и времени.

надеюсь, это поможет.


это не совсем красивое решение. На самом деле, это довольно сложно реализовать, но это, безусловно, дает полиномиальную сложность. Хотя сложность также велика (N^5*k-моя приблизительная оценка), кто-то может найти способ улучшить ее или найти здесь идею для лучшего решения. Или вам может быть достаточно: даже эта сложность намного лучше, чем bruteforce.

Примечание: оптимальное решение (set S) с КАСКО H включает все точки из исходного набора внутри H. В противном случае, мы могли бы выбросить одну из пограничных пунктов H и включите эту пропущенную точку, уменьшив периметр.
(обновление так же, как "оптимизация" mbeckish отправлено)

предположение: нет двух точек из набора образуют вертикальную линию. Это может быть легко достигнуто путем поворота всего набора точек на некоторый иррациональный угол вокруг начала координат.

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

теперь давайте возьмем один сегмент из top часть этого корпуса и один из bottom часть. Назовем эти два сегмента middle segments и периметр правой части этого корпуса -right периметра.
Примечание: эти два сегмента-это все, что нам нужно знать о правой части нашей выпуклой оболочки, чтобы продолжать строить ее слева. Но только два очка вместо 4-х не хватает: мы не можем поддерживать состояние 'convexness' таким образом.

это приводит к решению. Для каждого набора точек {p0, p1, p2, p3} и числа i (i right периметр, который может быть достигнут, если [p0, p1], [p2, p3] два middle сегментов и i - это количество точек в right часть этого решения (включая те, что внутри него, а не только на границе).

идем через все точки справа налево. Для каждого нового пункта p мы проверяем все комбинации точек {p0, p1, p2, p3} такие, что точка p может продолжать этот корпус влево (либо на top или bottom часть). Для каждого такого набора и размера i, мы уже храним оптимальный размер периметра (см. пункт выше).

Примечание: если добавить пункт p до right-hull сформированный точками {p0, p1, p2, p3}, вы увеличите размер набора i по крайней мере на 1. Но иногда это число будет > 1: вам нужно будет включить все точки в треугольник {p, p0, p2}. Они не на корпусе, а внутри.

алгоритм закончен :) кроме того, несмотря на страшную сложность, вы можете заметить, что не все сегменты [p0, p1], [p2, p3] могут быть middle сегменты: это должно существенно сократить фактическое время вычислений.

обновление это обеспечивает только оптимальный размер периметра, а не сам набор. Но найти набор очень просто: для каждого "состояния" над вами сохраняется не только размер периметра, но и последняя добавленная точка. Затем вы можете "отследить" свое решение. Это довольно стандартный трюк, я полагаю, это не проблема для Вас, Вы, кажется, хорошо разбираетесь в алгоритмах:)

обновление 2 это по существу DP (динамическое программирование), только немного раздутый


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

доказательство:

Если ваш выпуклый корпус содержит точки, которые не находятся в вашем подмножестве, то удалите точку из вашего подмножества, которое находится на корпусе, и замените ее точкой внутри корпуса. Это даст корпус равного или меньшего периметра.


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

jarvis(S)
   pointOnHull = leftmost point in S
   i = 0
   repeat
      P[i] = pointOnHull
      endpoint = S[0]         // initial endpoint for a candidate edge on the hull
      for j from 1 to |S|-1
         if (S[j] is on left of line from P[i] to endpoint)
            endpoint = S[j]   // found greater left turn, update endpoint
      i = i+1
      pointOnHull = endpoint
   until endpoint == P[0]      // wrapped around to first hull point

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

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

опубликовано решение решает для выпуклой оболочки с наименьшим количеством очков. Любой корпус с большим количеством точек будет иметь более длинный периметр, и я неправильно понял вопрос о поиске минимального периметра, а не минимального периметра для набора с K точками.

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