[二分+半平面交]POJ 3525 Most Distant Point from the Sea 题解

版权声明:本文为博主原创文章,欢迎转载。 https://blog.csdn.net/try__jhf/article/details/82693963

题目大意

给出一个 n 条边的凸多边形,求这个凸多边形离边界最远的点与边界之间的距离, n 100

题目分析

这道题有多种写法,这里为其中一种方法,对于凸多边形上一点到边界的距离肯定是取所有边到点的距离中取最小值,最小取最大?二分!我们可以尝试二分查找答案x验证。对于每条边界,都要有一部分是与边界距离大于等于x的,这些点在一起构成了一个小的凸多边形,或者可以说,构成了一个半平面,这样的话就可以把边界往内推,
这里写图片描述

然后半平面交求是否为非空即可。

不过这个方法缺陷也很多,比如推比较麻烦,而且容易精度卡住,比如下面这份代码在自己造的数据上现在还卡着,不过把POJ上的菜鸡数据A掉还是没问题的。

示例代码

题目传送门

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double pi=3.1415926535,eps=1e-15;
int dcmp(double x){
    if (fabs(x)<eps) return 0;
    return x>0?1:-1;
}
struct fdata{
    double x,y;
    fdata (double x=0,double y=0):x(x),y(y){}
}p[105],po[105];
double dot(const fdata a,const fdata b){return a.x*b.x+a.y*b.y;}
double cross(const fdata a,const fdata b){return a.x*b.y-a.y*b.x;}
double leng(const fdata a){return sqrt(dot(a,a));}
struct hdata{
    fdata p,v; double ang;
    hdata (){}
    hdata (fdata pi,fdata vi){
        p=pi; v=vi; ang=atan2(v.y,v.x); v.y=sin(ang); v.x=cos(ang);
    }
    bool operator < (const hdata b)const{return ang<b.ang;}
}ln[105],lne[105],que[105];
fdata operator + (const fdata a,const fdata b){return fdata(a.x+b.x,a.y+b.y);}
fdata operator - (const fdata a,const fdata b){return fdata(a.x-b.x,a.y-b.y);}
fdata operator * (const fdata a,const double b){return fdata(a.x*b,a.y*b);}
bool pd_lft(const hdata a,const fdata p){return dcmp(cross(a.v,p-a.p))>=0;}
fdata getJ(const hdata a,const hdata b){
    fdata u=a.p-b.p;
    double t=cross(b.v,u)/cross(a.v,b.v);
    return a.p+a.v*t;
}
double L,R,mid,ans;
int n,m,hed,til;
void _init(){
    for (int i=1;i<=n;i++) scanf("%lf%lf",&po[i].x,&po[i].y); po[n+1]=po[1];
    for (int i=1;i<=n;i++) ln[i]=hdata(po[i],po[i+1]-po[i]);
}
fdata RotateV(fdata a,double rad){
    return fdata(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
hdata moveL(hdata a,double L){
    fdata v=RotateV(a.v,pi/2);
    return hdata(a.p+v*L,a.v);
}
bool _check(double x){
    for (int i=1;i<=n;i++) lne[i]=moveL(ln[i],x-(1e-11));
    sort(lne+1,lne+n+1); hed=til=1; que[1]=lne[1];
    for (int i=2;i<=n;i++){
        while (hed<til&&!pd_lft(lne[i],p[til-1])) til--;
        while (hed<til&&!pd_lft(lne[i],p[hed])) hed++;
        que[++til]=lne[i];
        if (!dcmp(cross(que[til].v,que[til-1].v))){
            til--;
            if (pd_lft(que[til],lne[i].p)) que[til]=lne[i];
        }
        if (hed<til) p[til-1]=getJ(que[til-1],que[til]);
    }
    while (hed<til&&!pd_lft(que[hed],p[til-1])) til--;
    return til-hed>1;
}
void _solve(){
    L=ans=0.0; R=1e4;
    while (R-L>=1e-9){
        mid=(R-L)/2+L;
        if (_check(mid)) ans=L=mid;
        else R=mid;
    }
    printf("%.6lf\n",ans);
}
int main()
{
    freopen("island.in","r",stdin);
    freopen("island.out","w",stdout);   
    while (scanf("%d",&n)==1&&n){
        _init();
        _solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/82693963
今日推荐