poj 3525 Most Distant Point from the Sea(将边内缩)(半平面交求多边形中可以放入最大的圆的半径)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84311672

题目链接:http://poj.org/problem?id=3525

题意:在凸边形内找出一点,使得到多边形边界的距离最大。

题解:

参考博客:https://blog.csdn.net/zuzhiang/article/details/78404556

转化为求多边形内可以放入的最大的圆的半径。二分求解。

///半平面交

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=111;
struct point
{
    double x,y;
    point(){}
    point(double _x,double _y){
        x=_x;y=_y;
    }
}poly[maxn];///存储半平面交后的交点

point operator + (point a,point b) { return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) { return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p) { return point(a.x/p,a.y/p);}

bool operator < (const point &a,const point &b){
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator == (const point &a,const point &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}


double Cross(point P,point Q)
{
    return P.x*Q.y-P.y*Q.x;
}

double Length(point A) { return sqrt(A.x*A.x+A.y*A.y);}

struct LINE
{
    point s,t;
    double angle;
     LINE(){}
    LINE(point _s,point _t){
        s=_s;t=_t;
        angle=atan2(t.y-s.y,t.x-s.x);
    }
}L[maxn],dq[maxn],trans[maxn];///存储向量,半平面交时用到的双端队列dq

point Getlinenode(LINE a,LINE b)
{

    point P=a.s,v=a.t-a.s; ///点,向量
    point Q=b.s,w=b.t-b.s;
    point u=P-Q;
    double t=Cross(w,u)/Cross(v,w);
    return P+v*t;
}
bool cmp(LINE P,LINE Q) ///两向量方向相同,靠下的优先
{
    if(fabs(P.angle-Q.angle)<esp)
        return Cross(P.s-P.t,Q.s-P.t)>esp;
    return P.angle<Q.angle;
}


bool Onright(LINE L,point p){ ///判断点p在直线L的右边,
    return Cross(L.s-L.t,p-L.t)>esp;
}

int Half(int n,int &m)
{
    sort(L,L+n,cmp);
    int l=0,r=1;
    m=1;
    for(int i=1;i<n;++i)///筛掉同斜率,保留靠下的向量,其余不要
        if(fabs(L[i].angle-L[i-1].angle)>esp)L[m++]=L[i];
    n=m;
    m=0;
    dq[0]=L[0],dq[1]=L[1];
    for(int i=2;i<n;++i)
    {
        if(dcmp(Cross(dq[r].s-dq[r].t,dq[r-1].s-dq[r-1].t))==0||dcmp(Cross(dq[l].s-dq[l].t,dq[l+1].s-dq[l+1].t))==0) return;

        
        ///交点在直线的右边,舍去
        while(l<r&&Onright(L[i],Getlinenode(dq[r],dq[r-1]))>0)--r;
        while(l<r&&Onright(L[i],Getlinenode(dq[l],dq[l+1]))>0)++l;
        dq[++r]=L[i];
    }

    ///判断下头尾向量
    while(l<r&&Onright(dq[l],Getlinenode(dq[r],dq[r-1]))>0)--r;
    while(l<r&&Onright(dq[r],Getlinenode(dq[l],dq[l+1]))>0)++l;

    if(r-l<=1) return 0;
    return 1;
//    dq[++r]=dq[l];///将头向量加到尾部
//    for(int i=l;i<r;++i)
//        poly[m++]=Getlinenode(dq[i],dq[i+1]);///存储m+1个(范围在[0,m])半平面交点
}

void Change(int n,double h) ///将所有边往内缩进h距离
{
    double dx,dy,len;

    for(int i=0;i<n;i++)
    {
        len=Length(trans[i].s-trans[i].t);
        dx=(trans[i].s.y-trans[i].t.y)/len*h;
        dy=(trans[i].t.x-trans[i].s.x)/len*h;

        L[i].s.x=trans[i].s.x+dx;
        L[i].s.y=trans[i].s.y+dy;
        L[i].t.x=trans[i].t.x+dx;
        L[i].t.y=trans[i].t.y+dy;
        L[i].angle=trans[i].angle;
    }
}

double BSearch(int n) ///二分搜索
{
    double l=0,r=20000,mid;
    int m;
    while(l+esp<r)
    {
        mid=(l+r)/2.0;
        Change(n,mid);
        if(Half(n,m)) l=mid;
        else r=mid;
    }
    return l;
}
int main()
{
    int n,m,t;
    while(scanf("%d",&n)&&n)
    {

        for(int i=0;i<n;++i)
            scanf("%lf%lf",&poly[i].x,&poly[i].y);
        poly[n]=poly[0];
        for(int i=0;i<n;++i)
        {
            trans[i]=LINE(poly[i],poly[i+1]);
        }
       printf("%.6f\n",BSearch(n));
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/84311672
今日推荐