以下代码段取自here。这是此问题的解决方案HDU 2823。
#define eps 1e-9
double rc(point pp[],point qq[],int n,int m)
{
int q=0;
int p=0;
for(int i=0;i<n;i++)
if(pp[i].y-pp[p].y<-eps)
p=i;
for(int i=0;i<m;i++)
if(qq[i].y-qq[q].y>eps)
q=i;
pp[n]=pp[0];
qq[m]=qq[0];
double tmp,ans=1e99;
for(int i=0;i<n;i++)
{
while((tmp=cross(pp[p+1],qq[q+1],pp[p])-cross(pp[p+1],qq[q],pp[p]))>eps)
q=(q+1)%m;
if(tmp<-eps)
ans=min(ans,dist_p_to_seg(qq[q],pp[p],pp[p+1]));
else
ans=min(ans,dist_seg_to_seg(pp[p],pp[p+1],qq[q],qq[q+1]));
p=(p+1)%n;
}
return ans;
}
pp[]
和qq[]
是两个不同的凸包。 p
是pp
凸包的最高点,q
是qq
凸包的最低点。
我似乎无法理解这一行:
while((tmp=cross(pp[p+1],qq[q+1],pp[p])-cross(pp[p+1],qq[q],pp[p]))>eps)
q=(q+1)%m;
他想要达到什么目标?
答案 0 :(得分:1)
函数cross(a,b,c)是找到以下矩阵的行列式,
| a.x a.y 1 |
| b.x b.x 1 | = 2 * A
| c.x c.y 1 |
其中A是三角形a,b,c的签名区域。 行列式的符号也告诉我们3个点是顺时针方向还是顺时针方向。 see here for an explanation
让我们像这样重写,
triA ← cross(pp[p+1],qq[q+1],pp[p])
triB ← cross(pp[p+1],qq[q],pp[p])
// This is equivalent to,
// just to make it a bit clearer
triA ← cross(pp[p], pp[p+1], qq[q+1])
triB ← cross(pp[p], pp[p+1], qq[q])
因此它检查由{em} 的一侧形成的三角形qq
上的最低点是否小于同一侧形成的三角形和qq的下一个最高点
如果是,请选择qq中的下一个点为q
并继续。 -i.e.选择q
,以使q
与<p, p+1>
的垂直距离最小化。
对于给定的一方<p, p+1>
,在本地最小化后,对pp
的所有边重复此操作。在每个步骤中保持当前边之间的最小距离。
这是一种找到两个凸包之间最小间距的 shaky 方式。直觉是正确的 - 正确的是它理解它很简单(这个想法,不是有问题的代码),对于凸多边形来说非常普遍,并且非常有用的各种问题(参见参考资料)下面);但是,我觉得这可以用更有效和易于理解的方式编写。
本文充分说明了这些想法背后的直觉 "Solving Geometric Problems with the Rotating Calipers" - Toussaint G。