poj3608 凸包间最近距离 旋转卡壳

网上代码,卡壳部分的实现还未太懂

先留着

http://blog.sina.com.cn/s/blog_732dd9320100sjtv.html

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define N 10015
#define PR 1e-8
struct TPoint
{
    double x,y;
    TPoint(){};
    TPoint(double _x,double _y):x(_x),y(_y){}
    TPoint operator-(const TPoint p){return TPoint(x-p.x,y-p.y);}
}s;
struct TPolygon
{
    int n;
    TPoint p[N];
}ply1,ply2;
int dblcmp(double a) {return fabs(a)<PR?0:a>0?1:-1;}
double MIN(double a,double b) {return a<b?a:b;}
double dist(TPoint a,TPoint b)//两点距
{
    TPoint c(a-b);
    return sqrt(c.x*c.x+c.y*c.y);
}
double cross(TPoint a,TPoint b,TPoint c)//叉积
{
    TPoint s(b-a),t(c-a);
    return s.x*t.y-s.y*t.x;
}
bool cmop(TPoint a,TPoint b)//x、y排序
{
    if(fabs(a.x-b.x)<PR) return a.y<b.y;
    else return a.x<b.y;
}
bool cmp(TPoint a,TPoint b)//叉积内排序
{
    int d1=dblcmp(cross(s,a,b));
    return d1>0||(d1==0&&dist(s,a)<dist(s,b));
}
TPolygon graham(TPolygon ply)//凸包
{
    int i,j,k;
    sort(ply.p,ply.p+ply.n,cmop);
    s=ply.p[0]; k=2;
    sort(ply.p+1,ply.p+ply.n,cmp);
    for(i=2,k=2;i<ply.n;i++)
    {
        while(k>1&&(dblcmp(cross(ply.p[k-2],ply.p[i],ply.p[k-1])))>=0) k--;
        ply.p[k++]=ply.p[i];
    }
    ply.n=k;
    return ply;
}
double disps(TPoint a,TPoint b,TPoint c)//点到线段的最近距离
{
    TPoint s(a-b),t(c-b);
    if(s.x*t.x+s.y*t.y<0) return dist(a,b);
    s=(a-c); t=(b-c);
    if(s.x*t.x+s.y*t.y<0) return dist(a,c);
    return fabs(cross(a,b,c))/(dist(b,c));
}
double disss(TPoint a,TPoint b,TPoint c,TPoint d)//两条线段最近距离
{
    return MIN(MIN(disps(a,c,d),disps(b,c,d)),MIN(disps(c,a,b),disps(d,a,b)));
}
double solve(TPolygon pl,TPolygon pr,int p,int q)//旋转卡壳,求凸边形最近距离
{
    int i;
    double tmp,min=1e90;
    pl.p[pl.n]=pl.p[0]; pr.p[pr.n]=pr.p[0];
    for(i=0;i<pl.n;i++)
    {
        while((tmp=cross(pl.p[p+1],pr.p[q+1],pl.p[p])-cross(pl.p[p+1],pr.p[q],pl.p[p]))>PR)
            q=(q+1)%pr.n;
        if(tmp<-PR) min=MIN(min,disps(pr.p[q],pl.p[p],pl.p[p+1]));
        else min=MIN(min,disss(pl.p[p],pl.p[p+1],pr.p[q],pr.p[q+1]));
        p=(p+1)%pl.n;
    }
    return min;
}
void gettop(TPolygon pl,TPolygon pr,int &l,int &r)//得到最下和最上点
{
    int i;
    l=r=0;
    for(i=0;i<pl.n;i++)
    {
        if((dblcmp(pl.p[i].y-pl.p[l].y))<0) l=i;
    }
    for(i=0;i<pr.n;i++)
    {
        if((dblcmp(pr.p[i].y-pr.p[r].y))>0) r=i;
    }
}
int main()
{
    while(scanf("%d%d",&ply1.n,&ply2.n),ply1.n&&ply2.n)
    {
        int i,l,r;
        for(i=0;i<ply1.n;i++) scanf("%lf%lf",&ply1.p[i].x,&ply1.p[i].y);
        for(i=0;i<ply2.n;i++) scanf("%lf%lf",&ply2.p[i].x,&ply2.p[i].y);
        ply1=graham(ply1);
        ply2=graham(ply2);
        gettop(ply1,ply2,l,r);
        double mindis=MIN(solve(ply1,ply2,l,r),solve(ply2,ply1,r,l));//最近距离
        printf("%.5lf\n",mindis);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值