旋转卡壳的确很卡人。现在本人学旋转卡壳还在初级阶段。但是这是算法的效率的确很高,所有必需得学会
我想说的是旋转卡壳求凸包的最近点对距离。大体思路如下:
对于给定的点,调整为逆时针方向;
一个P凸包中找纵坐标最小的点,在另一个Q凸包中找纵坐标最大的点;
进行卡壳处理,具体处理应为这样:
在p中纵坐标的最小点与之相邻的下标大一点与Q中纵坐标最大点组成三角形,再与Q中纵坐标最大点相邻的点下标大一的点组成另一个三角形。判断这两个三角形的面积的大小,进行旋转卡壳;如果卡不下去,就求距离,求距离时,分情况来求,可能是点到直线的距离,也可能卡壳的两条线平行,这样就直线间的距离。
求点到直线的距离,还有就是线到线段距离时候,需要处理一下,我觉得对我来说,这是难点。
代码如下,做的时候,叉积一直搞错,得注意...TT....
我想说的是旋转卡壳求凸包的最近点对距离。大体思路如下:
对于给定的点,调整为逆时针方向;
一个P凸包中找纵坐标最小的点,在另一个Q凸包中找纵坐标最大的点;
进行卡壳处理,具体处理应为这样:
在p中纵坐标的最小点与之相邻的下标大一点与Q中纵坐标最大点组成三角形,再与Q中纵坐标最大点相邻的点下标大一的点组成另一个三角形。判断这两个三角形的面积的大小,进行旋转卡壳;如果卡不下去,就求距离,求距离时,分情况来求,可能是点到直线的距离,也可能卡壳的两条线平行,这样就直线间的距离。
求点到直线的距离,还有就是线到线段距离时候,需要处理一下,我觉得对我来说,这是难点。
代码如下,做的时候,叉积一直搞错,得注意...TT....
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
#define N 10002
#define EPS 1e-10
struct point
{
double x;
double y;
}pn[N],pm[N];
double dis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
double det(double x1,double y1,double x2,double y2)
{
return x1*y2-x2*y1;
}
double cross(point a,point b,point c)
{
return det(a.x-c.x,a.y-c.y,b.x-c.x,b.y-c.y);
}
double dot(point a,point b)
{
return a.x*b.x+a.y*b.y;
}
double min(double a,double b)
{
return a>b?b:a;
}
void adjust(point *p,int n)
{
for(int i=0;i<n-2;i++)
{
int res=cross(p[i+1],p[i+2],p[i]);
if(res>EPS)return;
else if(res<-EPS)
{
reverse(p,p+n);
return;
}
}
}
double point_to_seg(point a,point b,point c)
{
point ab,ac;
ab.x=b.x-a.x;
ab.y=b.y-a.y;
ac.x=c.x-a.x;
ac.y=c.y-a.y;
double f=dot(ab,ac);
if(f<0)return dis(a,c);
double f1=dot(ab,ab);
if(f>f1)return dis(b,c);
f=f/f1;
point d;
d.x=a.x+ab.x*f;
d.y=a.y+ab.y*f;
return dis(d,c);
}
double seg_to_seg(point a1,point b1,point a2,point b2)
{
return min(min(point_to_seg(a1,b1,a2),point_to_seg(a1,b1,b2)),min(point_to_seg(a2,b2,a1),point_to_seg(a2,b2,b1)));
}
double rc(point *p1,int n,point *p2,int m)
{
int s1=0,s2=0;
for(int i=0;i<n;i++)
{
if(p1[i].y-p1[s1].y<-EPS)
{
s1=i;
}
}
for(int i=0;i<m;i++)
{
if(p2[i].y-p2[s2].y>EPS)
{
s2=i;
}
}
p1[n]=p1[0];
p2[m]=p2[0];
double res,ans=1e20;
for(int i=0;i<n;i++)
{
while((res=cross(p2[s2],p1[s1+1],p1[s1])-cross(p2[s2+1],p1[s1+1],p1[s1]))>EPS)
{
s2=(s2+1)%m;
}
if(res<-EPS)ans=min(ans,point_to_seg(p1[s1],p1[s1+1],p2[s2]));
else ans=min(ans,seg_to_seg(p1[s1],p1[s1+1],p2[s2],p2[s2+1]));
s1=(s1+1)%n;
}
return ans;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&pn[i].x,&pn[i].y);
}
for(int i=0;i<m;i++)
{
scanf("%lf%lf",&pm[i].x,&pm[i].y);
}
adjust(pn,n);
adjust(pm,m);
printf("%.5lf\n",sqrt(min(rc(pn,n,pm,m),rc(pm,m,pn,n))));
}
return 0;
}