Uvalive 3890 Most Distant Point from the Sea(半平面交+二分)

62 篇文章 0 订阅
19 篇文章 0 订阅

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1891

思路:

1.求一点到凸包边界最远,即求最大内切圆半径。

2.二分半径r,讲凸包上边像内平移(点p+(normal vector)*r,方向向量v),求半平面交。若交点大于0,此时半径仍可扩大(即所求圆并未与边相切)。若交点等于0,则此时可能存在一内切圆,继续缩小半径。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;
const double eps=1e-6;
const double PI=acos(-1.0);

const int maxn=200;

struct Point
{
    double x,y;
    Point() {}
    Point(double x,double y):x(x),y(y) {}
    void read()
    {
        scanf("%lf%lf",&x,&y);
    }
};

typedef Point Vector;

Vector operator - (Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
Vector operator * (Vector A,double t)
{
    return Vector(A.x*t,A.y*t);
}

double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}

int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return x<0?-1:1;
}

double Dot(Vector A,Vector B)
{
  return A.x*B.x+A.y*B.y;
}

double Length(Vector A)
{
  return sqrt(Dot(A,A));
}

Vector Normal(Vector A)
{
  double L=Length(A);
  return Vector(-A.y/L,A.x/L);
}

struct Line
{
    Point P;
    Vector v;
    double ang;
    Line() {}
    Line(Point p,Vector v):P(p),v(v)
    {
        ang=atan2(v.y,v.x);
    }
    bool operator < (const Line& L) const
    {
        return ang<L.ang;
    }
    Line Move(double d)
    {
        Vector tmp=Normal(v);
        return Line(P+tmp*d,v);
    }
};

bool onLeft(Line L,Point p)
{
    return Cross(L.v,p-L.P)>0;
}

Point getIntersection(Line a,Line b)
{
    Vector u=a.P-b.P;
    double t=Cross(b.v,u)/Cross(a.v,b.v);
    return a.P+a.v*t;
}

int Half_Plane_Intersection(Line* L,int n,Point* poly)
{
    sort(L,L+n);
    int first,last;
    Point* p=new Point[n];
    Line* q=new Line[n];
    q[first=last=0]=L[0];
    for(int i=1; i<n; i++)
    {
        while(first<last&&!onLeft(L[i],p[last-1])) last--;
        while(first<last&&!onLeft(L[i],p[first])) first++;
        q[++last]=L[i];
        if(fabs(Cross(q[last].v,q[last-1].v))<eps)
        {
            last--;
            if(onLeft(q[last],L[i].P)) q[last]=L[i];
        }
        if(first<last) p[last-1]=getIntersection(q[last-1],q[last]);
    }
    while(first<last&&!onLeft(q[first],p[last-1])) last--;
    if(last-first<=1) return 0;
    p[last]=getIntersection(q[last],q[first]);

    int m=0;
    for(int i=first; i<=last; i++)
        poly[m++]=p[i];
    return m;
}

int n;
Line l[maxn];
Point p[maxn];

int check(double r)
{
    for(int i=0; i<n; i++)
    {
        Vector v=Normal(p[(i+1)%n]-p[i]);
        l[i]=Line(p[i],p[(i+1)%n]-p[i]).Move(r);
    }
    Point poly[maxn];
    return Half_Plane_Intersection(l,n,poly)==0;
}

double solve()
{
    double L=0,R=20000,ans;
    while(dcmp(R-L)!=0)
    {
        double mid=(L+R)/2;
        if(check(mid))
        {
            ans=mid;
            R=mid;
        }
        else
        {
            L=mid;
        }
    }
    return ans;
}

int main()
{
#ifdef debu
    freopen("in.txt","r",stdin);
#endif // debug
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(int i=0; i<n; i++) p[i].read();
        printf("%.6f\n",solve());
    }
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值