poj 3608 旋转卡壳求两凸包间的最近距离

来源:互联网 发布:泰国贫富差距知乎 编辑:程序博客网 时间:2024/04/27 14:07
旋转卡壳的确很卡人。现在本人学旋转卡壳还在初级阶段。但是这是算法的效率的确很高,所有必需得学会
我想说的是旋转卡壳求凸包的最近点对距离。大体思路如下:
        对于给定的点,调整为逆时针方向;
        一个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-10struct 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;}


原创粉丝点击