求两个相互分离凸包公切线的线性算法

求两个相互分离凸包公切线的线性算法

转载自:http://www.cnblogs.com/sudoleo/archive/2010/07/22/1783326.html

 

《算法艺术与信息学竞赛》 刘汝佳 习题3.2.8

平面上有两个凸多边形A和B,相互分离且都不退化,求A和B的4条公切线。O(n^2)的算法是很显然的,但你能否有线性的做法呢?进一步地,联想本节读过的凸多边形判断形内形外的特殊性,能否尝试更快的算法?

求两个相互分离凸包公切线的线性算法_第1张图片

设凸多边形A和B的上外公切线为(Ai,Bj),切点分别为Ai和Bj,可知:A和B均在上外公切线(Ai,Bj)的右侧。进一步,“凸多边形A在(Ai,Bj)的右侧”等价于“Ai_next和Ai_pre均在(Ai,Bj)的右侧(或其中一个在右侧,另一个共线)”,简单起见,定义Ai_next为“Ai的next方向的顶点中第一个不与(Ai,Bj)共线的顶点”,同理Ai_pre,Bj_next,Bj_pre。“(Ai,Bj)是凸多边形A和B的上外公切线”这一命题等价于“Ai_next,Ai_pre,Bj_next,Bj_pre均在(Ai,Bj)的右侧”。 

 

伪代码:

up_left = a[i]; // 取凸多边形A上任一点a[i],初始边的起点
up_right = b[j]; // 取凸多边形B上任一点b[j],初始边的终点

while ( 1 )
{
left_next
= a[up_left_next]; // 凸多边形A上顶点up_left的next方向上第一个不与(up_left, up_right)共线的顶点
left_pre = a[up_left_pre]; // 凸多边形A上顶点up_left的pre方向上第一个不与(up_left, up_right)共线的顶点
right_next = b[up_right_next]; //
right_pre = b[up_right_pre]; //

if ( left_next 在 (up_left, up_right) 右侧 )
if ( left_pre 在 (up_left, up_right) 右侧 )
if ( right_next 在 (up_left, up_right) 右侧 )
if ( right_pre 在 (up_left, up_right) 右侧 )
break ; // (up_left, up_right)是上外公切线,结束
else up_right = right_pre;
else up_right = right_next;
else up_left = left_pre;
else up_left = left_next;
}
 

算法的复杂度是O(n),实际上,初始边的选择能提高算法的实际执行效率。

例如,左侧凸多边形A最右面的点作为初始边的始点,右侧凸多边形B最左面的点作为初始边的终点;
又如,求上外公切线的结果,作为求内公切线的初始边猜测,两条内公切线的下侧的点,又可以作为下外公切线初始边的始点和终点。这样猜测得到的初始边经过较少次数的“摆动”就可以得到结果。

 算法并未经大量实验验证,欢迎指正。求更好的算法。

 

你可能感兴趣的:(CGAL)