这不是一个很好的解决方案。事实上,实现起来相当痛苦,但它肯定会产生多项式复杂性。虽然复杂性也很大(n^5*k 是我的粗略估计),但有人可能会找到改进它的方法或在这里找到更好解决方案的想法。或者它可能对你来说就足够了:即使这种复杂性也比蛮力好得多。
注意S
:带外壳的最优解(集合)H
包括内部原始集合的所有点H
。否则,我们可以丢弃其中一个边界点H
并包括该错过的点,从而减少周长。
(更新就像发布的“优化” mbeckish)
假设:集合中没有两点形成一条垂直线。它可以通过围绕坐标原点将整组点旋转一些不合理的角度来轻松实现。
由于上述假设,任何复杂的船体都有一个最左边和一个最右边的点。此外,这两点将船体分为top
和bottom
部分。
现在,让我们从top
这个船体的一部分中取出一个片段,并从该部分中取出一个片段bottom
。让我们将这两个部分middle segments
和这个船体右侧部分的周长称为right
周长。
注意:这两个部分是我们需要了解的关于凸包右侧部分的所有信息,以便继续将其构建到左侧。但是只有两点而不是四点是不够的:我们不能以这种方式维持“凸”的条件。
它导致了一个解决方案。对于每组点 {p0, p1, p2, p3} 和数字i
(i <= k),我们存储如果 [p0, p1], [p2, p3] 是两个线段right
可以达到的最小周长,并且是此解决方案部分中的点(包括其中的点,不仅在边界上)。middle
i
right
我们从右到左遍历所有点。对于每个新点p
,我们检查点 {p0, p1, p2, p3} 的所有组合,以便点 p 可以将这个外壳继续向左(在该部分上top
或在该bottom
部分上)。对于每个这样的 set 和 size i
,我们已经存储了最佳周长尺寸(参见上面的段落)。
注意:如果您将点添加p
到right-hull
由点 {p0, p1, p2, p3} 形成的点,您将i
至少将集合大小增加 1。但有时这个数字将 > 1:您必须包括所有点三角形 {p, p0, p2}。它们不在船体上,而是在船体内。
算法结束 :) 此外,尽管复杂性令人恐惧,但您可能会注意到并非所有段 [p0, p1], [p2, p3] 都可以是middle
段:它应该会大大减少实际计算时间。
更新这仅提供最佳周长大小,而不是集合本身。但是找到集合很简单:对于上面的每个“状态”,您不仅存储周长大小,还存储最后添加的点。然后,您可以“追溯”您的解决方案。这是相当标准的把戏,我想这对你来说不是问题,你似乎擅长算法:)
update2 这个本质上是DP(动态编程),只是有点臃肿