在飞机上给出n个点。 No 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个点的结构。
答案 0 :(得分:9)
这可以在O(kn ^ 3)时间和O(kn ^ 2)空间中完成(如果你想要实际的点,可以在O(kn ^ 3)中完成。)
本文:http://www.win.tue.nl/~gwoegi/papers/area-k-gons.pdf
Eppstein等人提出的算法可以解决这个问题的最小周长和其他权重函数,如面积,内部角度之和等,这些函数遵循一定的约束条件,即使标题表示最小面积(参见周长的推论5.3)。 / p>基本思想是动态编程方法如下(阅读第4节的前几段):
假设S是给定的点集,Q是具有最小周长的k点的凸包。
令p1为Q的最底点,p2和p3为逆时针顺序的船体上的下一个点。
我们可以将Q分解为三角形p1p2p3和k-1点Q'的凸包(与p1p2p3三角形共用p1p3)。
主要观察结果是Q'对于k-1是最佳的,其中最下面的点是p1并且下一个点是p3并且Q'的所有点位于线p2->的同一侧。 P3。
因此为每个四元组(pi,pj,pk,m)保持4d最佳多边形阵列,以便
可以帮助我们找到m = k的最佳多边形。
本文详细描述了如何实现这一目标,以达到规定的时空范围。
希望有所帮助。
答案 1 :(得分:2)
这不是一个非常漂亮的解决方案。事实上,实现起来相当痛苦,但它肯定会给出多项式的复杂性。虽然复杂性也很大(n ^ 5 * k是我的粗略估计),但有人可能会找到一种方法来改进它,或者找到一个更好的解决方案。或者对你来说可能就足够了:即使这种复杂性也比暴力强大得多。
注意:带有S
的最佳解决方案(设置H
)包括来自H
内的orignal设置的所有点。否则,我们可以丢弃H
的一个边界点并包括那个遗漏点,减少周长
(更新就像'优化' mbeckish 一样)
假设:设置中没有两个点形成一条垂直线。通过围绕坐标原点的一些无理角旋转整组点可以很容易地实现。
由于上述假设,任何复杂的船体都有一个最左边和一个最右边的点。此外,这两点将船体划分为top
和bottom
部分。
现在,让我们从这个船体的top
部分和bottom
部分中取一个部分。我们将这两个段middle segments
和此船体右侧部分的周长称为right
周长。
注意:我们需要了解这两个部分,我们需要了解凸包的右侧部分,以便继续将其构建到左侧。但只有两点而不是4点是不够的:我们无法以这种方式维持“凸性”的条件。
导致解决方案。对于每组点{p0,p1,p2,p3}和数字i
(i <= k),我们存储可以实现的最小right
周长,如果[p0,p1],[p2] ,p3]是两个middle
段,i
是此解决方案的right
部分中的点数(包括其中的点,不仅在边界上)。
我们从右到左遍历所有点。对于每个新点p
,我们检查点{p0,p1,p2,p3}的所有组合,使得点p可以将此船体继续向左(在top
上或{{1部分)。对于每个这样的集合和大小bottom
,我们已经存储了最佳周长大小(参见上面的段落)。
注意:如果您将点i
添加到由{p0,p1,p2,p3}点组成的p
,您将增加集合大小{{1至少由1.但有时这个数字将是&gt; 1:你必须在三角形{p,p0,p2}中包含所有点。它们不在船体上,而在船体内部。
算法结束了:)此外,尽管可怕的复杂性,您可能会注意到并非所有段[p0,p1],[p2,p3]都可以是right-hull
段:它应该大大减少实际计算时间。
更新这仅提供最佳的周边尺寸,而不是设置本身。但是找到这个集很简单:对于上面的每个“状态”,你不仅存储周长大小,还存储最后一点。然后,您可以“追踪”您的解决方案。这是非常标准的技巧,我想这对你来说不是问题,你似乎擅长算法:)
update2 这基本上是DP(动态编程),只是有点臃肿
答案 2 :(得分:1)
一种可能的优化:您可以忽略其凸包含有不在子集中的点的任何子集。
证明:
如果您的凸包含有不在您的子集中的点,则从船体上的子集中移除一个点,并将其替换为船体内部的点。这将产生相等或更小周长的船体。
答案 3 :(得分:-2)
在平面情况下,您可以使用称为Jarvis march的算法,该算法具有最差的案例复杂度O(n ^ 2)。在此算法中,您开始在任意点构建外壳,然后检查下一个需要添加的点。伪代码取自wikipedia:
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所怀疑的,并且最类似于最长的路径问题。不幸的是,我缺乏提供有价值的减少的聪明才智。