题意:求两个凸包的最短距离
思路:将凸包逆时针化,寻找一个凸包的y最小的一个点,另一个凸包y最大的点,分别按逆时针旋转卡壳,更新最短距离。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define sqr(x) ((x)*(x))
#define maxn 10000+10
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
int dcmp(double x)
{
if(x<-eps) return -1;
else return x>eps;
}
struct cpoint
{
double x,y;
cpoint(){}
cpoint (double x,double y) :x(x),y(y){}
cpoint operator - (const cpoint &u) const {
return cpoint(x-u.x,y-u.y);
}
double operator * (const cpoint &u) const {
return x*u.y-y*u.x;
}
double operator ^ (const cpoint &u) const {
return x*u.x+y*u.y;
}
bool operator == (const cpoint &u) const {
return dcmp(x-u.x)==0&&dcmp(y-u.y)==0;
}
};
double cross (cpoint o,cpoint p,cpoint q)
{
return (p-o)*(q-o);
}
double dot(cpoint o,cpoint p,cpoint q)
{
return (p-o)^(q-o);
}
double dis(cpoint p,cpoint q)
{
return sqrt(sqr(p.x-q.x)+sqr(p.y-q.y));
}
double dissqr(cpoint p,cpoint q)
{
return sqr(p.x-q.x)+sqr(p.y-q.y);
}
double pointtoline(cpoint p0,cpoint p1,cpoint p2,cpoint &cp)
{
double d=dis(p1,p2);
double s=cross(p1,p2,p0)/d;
cp.x=p0.x+s*(p2.y-p1.y)/d;
cp.y=p0.y-s*(p2.x-p1.x)/d;
return fabs(s);
}
bool pointonsegment(cpoint p0,cpoint p1,cpoint p2)
{
return dcmp(cross(p0,p1,p2))==0&&dcmp(dot(p0,p1,p2))<=0;
}
cpoint bp;
double pointtoseg(cpoint p0,cpoint p1,cpoint p2)
{
cpoint cp;
double d=pointtoline(p0,p1,p2,cp);
if(pointonsegment(cp,p1,p2)) return d;
else return min(dis(p0,p1),dis(p0,p2));
}
double dispallseg(cpoint p0,cpoint p1,cpoint p2,cpoint p3)
{
return min(min(pointtoseg(p0,p2,p3),pointtoseg(p1,p2,p3)),min(pointtoseg(p2,p0,p1),pointtoseg(p3,p0,p1)));
}
void anticlockwise(cpoint cp[],int n)
{
for(int i=0;i<n-2;i++)
{
double t=cross(cp[i],cp[i+1],cp[i+2]);
if(dcmp(t)>0) return ;
if(dcmp(t)<0)
{
reverse(cp,cp+n);
return ;
}
}
}
double rotating(cpoint ch1[],int n,cpoint ch2[],int m)
{
int p=0,q=0;
for(int i=0;i<n;i++)
if(dcmp(ch1[i].y-ch1[p].y)<0)
p=i;
for(int i=0;i<m;i++)
if(dcmp(ch2[i].y-ch2[i].y)>0)
q=i;
ch1[n]=ch1[0];
ch2[m]=ch2[0];
double tmp,res=1e99;
for(int i=0;i<n;i++)
{
while((tmp=cross(ch1[p],ch1[p+1],ch2[q+1])-cross(ch1[p],ch1[p+1],ch2[q]))>eps)
q=(q+1)%m;
if(dcmp(tmp)<0)
res=min(res,pointtoseg(ch2[q],ch1[p],ch1[p+1]));
else
res=min(res,dispallseg(ch1[p],ch1[p+1],ch2[q],ch2[q+1]));
p=(p+1)%n;
}
return res;
}
cpoint ch1[maxn],ch2[maxn];
int n,m;
double solve()
{
anticlockwise(ch1,n);
anticlockwise(ch2,m);
return min(rotating(ch1,n,ch2,m),rotating(ch2,m,ch1,n));
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
for(int i=0;i<n;i++)
scanf("%lf %lf",&ch1[i].x,&ch1[i].y);
for(int i=0;i<m;i++)
scanf("%lf %lf",&ch2[i].x,&ch2[i].y);
printf("%.5lf\n",solve());
}
return 0;
}