题目大意:给出两个点集,求出两个凸包后,求两个凸包的最近距离。需要特判两个凸包内含和相交各种乱七八糟的情况。
题解:旋转卡壳求两凸包的最近距离
考虑如下的算法, 算法的输入是两个分别有m和n个顺时针给定顶点的凸多边形P和Q。
1.计算P上y坐标值最小的顶点(称为 yminP )和Q上y坐标值最大的顶点(称为 ymaxQ)。
2.为多边形在 yminP 和 ymaxQ 处构造两条切线 LP 和 LQ 使得他们对应的多边形位于他们的右侧。
此时 LP 和 LQ 拥有不同的方向, 并且 yminP 和 ymaxQ 成为了多边形间的一个对踵点对。
3.计算距离(yminP,ymaxQ) 并且将其维护为当前最小值。
4.顺时针同时旋转平行线直到其中一个与其所在的多边形的边重合。
5.如果只有一条线与边重合, 那么只需要计算“顶点-边”对踵点对和“顶点-顶点”对踵点对距离。 都将他们与当前最小值
比较, 如果小于当前最小值则进行替换更新。如果两条切线都与边重合,那么情况就更加复杂了。如果边“交叠”,也就是
可以构造一条与两条边都相交的公垂线(但不是在顶点处相交), 那么就计算“边-边”距离。 否则计算三个新的“顶点-顶
点”对踵点对距离。 所有的这些距离都与当前最小值进行比较, 若小于当前最小值则更新替换。
6.重复执行步骤4和步骤5, 直到新的点对为(yminP,ymaxQ)。
7.输出最小距离。
#include
#include
#include
#include
#include
#define N 1003
#define eps 1e-8
using namespace std;
struct vector {
double x,y;
vector (double X=0,double Y=0){
x=X,y=Y;
}
}p[N],q[N],ch[N];
double ans;
int n,m;
typedef vector point;
vector operator -(vector a,vector b){return vector (a.x-b.x,a.y-b.y);}
vector operator +(vector a,vector b){return vector (a.x+b.x,a.y+b.y);}
vector operator *(vector a,double t){return vector (a.x*t,a.y*t);}
vector operator /(vector a,double t){return vector (a.x/t,a.y/t);}
bool operator <(vector a,vector b)
{
return a.x0) return len(v3);
return fabs(cross(v1,v2))/len(v1);
}
double distl(point p,point a,point b)
{
vector v=p-a; vector u=b-a;
return fabs(cross(v,u))/len(u);
}
void convexhull(point *a,int &n)
{
sort(a,a+n);
int cnt=0;
if (n==1) {
ch[cnt++]=a[0];
n=cnt;
for (int i=0;i1&&cross(ch[cnt-1]-ch[cnt-2],a[i]-ch[cnt-2])<=0) cnt--;
ch[cnt++]=a[i];
}
int k=cnt;
for (int i=n-2;i>=0;i--){
while (cnt>k&&cross(ch[cnt-1]-ch[cnt-2],a[i]-ch[cnt-2])<=0) cnt--;
ch[cnt++]=a[i];
}
cnt--;
n=cnt;
for (int i=0;iq[y].y)?i:y;
for (int i=0;i=0) t++;
if (t==n) return true;
else return false;
}
bool check()
{
for (int i=0;im) swap(n,m),swap(p,q);
if (n==1) {
if (m==1) ans=len(p[0]-q[0]);
else {
if (m==2) ans=dists(p[0],q[0],q[1]);
else {
if (pointin(p[0],q,m)) ans=0.0000;
else for (int i=0;i