分解为凸多边形

13

这个问题有些棘手。我编写了一个算法,用于将简单多边形分解为凸多边形,但现在我无法证明它不是最优的(即使用Steiner点(添加顶点)的最小凸多边形数)。我的教授坚称不能使用贪心算法,例如这个算法,但我想不出反例。

因此,如果有人能证明我的算法是次优的(或最优的),我会很感激。

用图片最容易解释我的算法(这些图片来自旧版本的次优解):

我的算法是,在点i周围延伸线段,直到延伸线段与对面边缘上的顶点相遇。

如果在这个范围内没有顶点,则创建一个新的顶点(红点)并连接到该点:

如果在这个范围内存在一个或多个顶点,则连接到最近的那个。这通常会产生具有最少凸多边形数量的分解:

但是,在某些情况下,它会失败 - 在下面的图中,如果它恰好首先连接中间绿色线,则会创建一个额外的不必要的多边形。对此,我建议双重检查我们添加的所有边缘(对角线),并检查它们是否仍然必要。如果不需要,则删除它:

然而,在某些情况下,这还不够。看看这个图:

用a-c替换a-b和c-d将得到更好的解。在这种情况下,没有边缘可供删除,因此这是一个问题。在这种情况下,我建议按优先顺序选择:在决定将一个凹顶点连接到哪个顶点时,应选择具有最高优先级的顶点:

优先级低)最近的定点

优先级中)最近的凹顶点

优先级高)在向后处理时也在范围内的最近凹顶点(难以解释)--

此图 中,我们可以看到凹顶点9选择连接12(因为它最近),但连接5会更好。由于顶点5和12都在由延伸线段10-9和8-9定义的范围内,但是应该给顶点5优先权,因为9在4-5和6-5给定的范围内,但不在13-12和11-12给定的范围内。也就是说,边缘9-12消除了顶点9处的凹顶点,但未消除顶点12处的凹顶点,但可以消除顶点5处的凹顶点,因此应该给予顶点5优先权。

使用这个修改后的版本可能仍然存在边缘5-12,但可以在后处理期间将其删除。

assume vertices in `poly` are given in CCW order
let 'good reflex' (better term??) mean that if poly[i] is being compared with poly[j], then poly[i] is in the range given by the rays poly[j-1], poly[j] and poly[j+1], poly[j]

for each vertex poly[i]
    if poly[i] is reflex
        find the closest point of intersection given by the ray starting at poly[i-1] and extending in the direction of poly[i] (call this lower bound)
        repeat for the ray given by poly[i+1], poly[i] (call this upper bound)

        if there are no vertices along boundary of the polygon in the range given by the upper and lower bounds
            create a new vertex exactly half way between the lower and upper bound points (lower and upper will lie on the same edge)
            connect poly[i] to this new point
        else
            iterate along the vertices in the range given by the lower and upper bounds, for each vertex poly[j]
                if poly[j] is a 'good reflex'
                    if no other good reflexes have been found
                        save it (overwrite any other vertex found)
                    else
                        if it is closer then the other good reflexes vertices, save it
                else
                    if no good reflexes have been found and it is closer than the other vertices found, save it
            connect poly[i] to the best candidate
        repeat entire algorithm for both halves of the polygon that was just split
// no reflex vertices found, then `poly` is convex
save poly

结果我还有一个情况没有考虑到:[图5]

除非我再添加一个检查来确保算法能够连接顶点1和4,否则我的算法将尝试去连接他们。因此,我建议使用我之前提到的优先级方案,将所有“在范围内”的元素都塞进一个优先级队列里,然后取出优先级最高的元素,检查它是否能够连接,如果不能,则弹出并使用下一个。我认为,如果我对其进行正确的优化,这将使我的算法复杂度为O(r n log n)。


我制作了一个网站来大致描述我的发现。由于我喜欢移动东西,所以趁热打铁。


如果您能提供一些(伪)代码,那将非常有帮助。从散文中很难看出正在发生什么。 - John Feminella
4个回答

2
我相信您所寻找的反例是常规五角星(例如,交替点具有共线线段)。根据评论的修订理解,一个修订后的答案:尝试一个锐角五角星(例如,只有对于你正在处理的弯曲点相对的手臂组成的三个点在被认为是“好的反射点”的范围内,手臂足够窄)。至少在纸上进行操作时,它似乎比最优解更好。然而,最终阅读您的代码让我想知道:“最接近”是什么意思(即最接近什么)?
请注意:即使我的答案被接受,它也不是我们最初想到的反例。正如@Mark在评论中指出的那样,它与最优解同时从四到五。
进一步思考后,我认为我还是正确的。可以通过确保一对手臂具有共线边缘来在锐角星形中保留四个最优限制。但是,即使进行了修补,该算法也会找到五个。我得到这个结果: 删除死亡ImageShack链接 而最优解是这个: 删除死亡ImageShack链接

你能提供更多细节吗?如果我没记错的话,最优解需要4个多边形,但是为什么我的算法会失败呢?我可能搞砸了边缘情况,但是假设我没有,我的算法应该允许一个凹顶点连接到共线顶点,并且一切都会很好地解决。 - mpen
哦,不好意思,我忘记在伪代码中包含它了。我已经写在“图3”下面了。我有一个部分实现的算法;它没有包括我最新的修订。所以暂时,我也在手动执行。 - mpen
这其实很容易看出来:http://img15.imageshack.us/img15/6057/star2j.gif 如果你稍微向外拉每个点a、c、d、f、h,它就符合你的条件了,但是此时“三角形”c、e、h不再是凸的,所以这就是我们能做到的最好效果。 - mpen
叹气 没错。哎呀!有没有办法将声望点数转让给其他人?如果您宁愿指定其他人为采纳答案,我可以这样做。 - MarkusQ
停一下。我想我最终是正确的。请参见上面的漂亮图片。 - MarkusQ
显示剩余11条评论

2
我认为你的算法不可能是最优的,因为它没有使用任何最优度量。你使用其他指标如“最近”的顶点和检查“必要”的对角线。

为了在你的算法和最优算法之间产生分歧,我们需要利用这个差距,寻找具有接近顶点的形状,这些形状会被分解得很差。例如(忽略线条,我在互联网上找到了这个):

凹多边形,形成G或U形状 http://avocado-cad.wiki.sourceforge.net/space/showimage/2007-03-19_-_convexize.png

你没有保护中心点跨越凹“间隙”的能力,这是多边形的外部

你的算法也相当复杂,可能过于复杂 - 就像复杂的代码一样,你可能会发现它存在错误,因为复杂的代码会做出复杂的假设。

考虑更广泛的初始阶段,将形状分解成更多、更简单的形状,比如三角形,然后使用迭代或遗传算法重新组合它们。你需要这样一个阶段来合并任何不必要的凸多边形之间的分割,到那时你可能已经将可能的分解限制为仅次优解决方案。
猜测大致如下:
1. 分解成三角形 2. 非确定性地生成许多重组 3. 计算质量度量(多边形数量) 4. 选择最佳x%的重组 5. 使用三角形部分地分解每个,生成一组新的重组 6. 从第4步重复直到达到某种收敛度量

对角线穿过间隙-请参阅“图5”下的小贴士。你说得很对,我一开始确实没注意到...但修复起来很容易,尽管会增加一些时间复杂度。将问题分解为三角形的问题在于,如果要移除一个凹顶点可能需要两条对角线。 - mpen
1
算法没有很好地分解...我的算法确保对角线被放置得足够好,以便在每次迭代中总是去除一个反射。你的算法虽然应该可以工作,但似乎也同样具有“神奇”的特性。你使用概率而不是具体的定理来实现最优性。 - mpen
太好了,这很好,但它看起来并不简单。我可以将我的(或您的)算法与Keil的一些想法结合起来,进一步增加最优解的可能性(例如,尝试所有“好的反应”,然后选择最佳解决方案),但我不确定您的解决方案是否具有这种优势。 - mpen
此外,也许最重要的是,您的解决方案没有利用斯坦纳点:p,这可能是我解决方案相对于其他算法最大的优势,即使它们并不经常发生 - 它们每次都可以将最终解决方案减少1个多边形,我相信。 - mpen
不是说你的算法有什么问题,只是我没有看到真正的优势。我的代码相当复杂,但是...看看Chazelle的算法吧:p 我认为甚至没有人费心去实现它,这太荒谬了:) 我想有时候我们必须承担这种代价。 - mpen
显示剩余2条评论

1
但是应该优先考虑顶点5,因为9在4-5和6-5给定的范围内。 如果4-5和6-5更加凸出,以至于9不在它们的范围内,那么根据你的规则,正确的做法是将9连接到12,因为12是最近的凹顶点,这将是次优的。

如果您的意思是在图4中将顶点4和6靠近,那么由3、4、5、9、10、11、12组成的多边形无论如何都不是凸多边形,如果9与5相连,则4、5、9将是凹角。因此,您现在看到的解决方案实际上是最优的。 - mpen

0

找到了 :( 它们实际上相当明显。


*失效的imageshack图片*

如果允许使用斯坦纳点,四叶草并不是最优选择...红色顶点可以被连接。


*失效的imageshack图像*

没有斯泰纳点,这甚至都不是最优的...5可以连接到14,省去了3-14、3-12和5-12的需要。这本来可以更好地组成两个多边形!真痛心啊!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接