(2分+半平面交) Most Distant Point from the Sea UVALive 3890

    题意,在大海的中央没有,有一个凸n边行的小岛。求出岛上离海上最远的距离。

题解:假设在岛上有一个点距离海平面为k。   那么这些点实际上是离每条边距离为k的直线围成的面积。  所以可以直接2分+半平面角。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<stdlib.h>
using namespace std;
const int mod=99999997;
const int mmax=200010;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3fffffff;


/*
---------------------------------------------------------------
double Dot(Vector A,Vector B)  点积
double Length(Vector A)  取模
double Angle(Vector A,Vector B) 夹角
double Cross(Vector A,Vector B) 叉积
double Area2(Point A,Point B,Point C) 有向面积
Vector Ratate(Vector A,double rad)  向量旋转
Vector Normal(Vector A) 法向量
Point GetLineIntersection(Point P,Point Q,Vector v,Vector w) 直线相交  line1 P+tv  line2 Q+tw
double Dis_Point_Line(Point P,Point A,Point B) 点到直线距离
Point GetLineProjection(Point P,Point A,Point B) 点在直线上投影
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) 线段规范相交
bool OnSegment(Point p,Point a1,Point a2)  点在直线上
double PolygonArea(Point *p,int n) 多边形面积
-----------------------------------------------------------------
*/
struct Point
{
    double x,y;
    Point (double x=0.0,double y=0.0):x(x),y(y) {}
    void read()
    {
        scanf("%lf %lf",&x,&y);
    }
};//点集
typedef Point Vector;
struct Line
{
    Point p;
    Vector v;
    double ang;
    Line(Point p=Point(0,0),Vector v=0):p(p),v(v)
    {
        ang=atan2(v.y,v.x);
    }
    Point point(double t)
    {
        return Point(p.x+v.x*t,p.y+v.y*t);
    }
    bool operator <(const Line &L) const
    {
        return ang<L.ang;
    }
};
//向量+向量=向量,向量+点=点
Vector operator + (Vector A,Vector B)
{
    return Vector(A.x+B.x,A.y+B.y);
}
//点-点=向量
Vector operator - (Point A,Point B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
//向量*数=向量
Vector operator * (Vector A,double p)
{
    return Vector(A.x*p,A.y*p);
}
//向量/数=向量
Vector operator / (Vector A,double p)
{
    return Vector(A.x/p,A.y/p);
}

int sgn(double x)// 符号函数
{
    if(fabs(x)<eps)
        return 0;
    return x<0?-1:1;
}


bool operator < (const Point &a,const Point &b)
{
    return a.x<b.x || (a.x==b.x&&a.y<b.y);
}
bool operator == (const Point &a,const Point &b)
{
    return sgn(a.x-b.x)==0&&sgn(a.y-b.y)==0;
}

//运算部分
double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
    return sqrt(Dot(A,A));
}
double Angle(Vector A,Vector B)
{
    return acos(Dot(A,B)/Length(A)/Length(B));
}
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
double Area2(Point A,Point B,Point C)
{
    return Cross(B-A,C-A);
}
//向量逆时针旋转
Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A) //单位法线
{
    double L=Length(A);
    return Vector(-A.y/L,A.x/L);
}

//直线相交  line1 P+tv  line2 Q+tw
Point GetLineIntersection(Point P,Point Q,Vector v,Vector w)
{
    Vector u=P-Q;
    double t=Cross(w,u) / Cross(v,w);
    return P+v*t;
}
//点到直线距离
double Dis_Point_Line(Point P,Point A,Point B)
{
    Vector v1=B-A,v2=P-A;
    return fabs(Cross(v1,v2)/Length(v1));
}
double Dis_Point_Line(Point P,Line L)
{
    Vector v1=L.v,v2=P-L.p;
    return fabs(Cross(v1,v2)/Length(v1));
}

double DistanceToSegment(Point p,Point a,Point b)
{
    if(a==b)
        return Length(p-a);
    Vector v1=b-a,v2=p-a,v3=p-b;
    if(sgn(Dot(v1,v2))<0) return Length(v2);
    if(sgn(Dot(v1,v3))>0) return Length(v3);
    return fabs(Cross(v1,v2)) / Length(v1);
}
//点在直线上的投影
Point GetLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    return A+v*(Dot(v,P-A) / Dot(v,v) );
}
//线段规范相交
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1);
    double c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return sgn(c1)*sgn(c2)<0&&sgn(c3)*sgn(c4)<0;
}

//点是否在线段上
bool OnSegment(Point p,Point a1,Point a2)
{
    return sgn(Cross(a1-p,a2-p))==0 && sgn(Dot(a1-p,a2-p))<0;
}

//多边形又向面积
double PolygonArea(Point *p,int n)
{
    double area=0.0;
    for(int i=1;i<n-1;i++)
        area+=Cross(p[i]-p[0],p[i+1]-p[0]);
    return area/2;
}

/*

圆和球相关
-------------------------------------------------

-------------------------------------------------

*/

struct Circle
{
    Point c;
    double r;
    Circle(Point c=Point(0,0),double r=0): c(c),r(r) {}
    Point point(double a)
    {
        return Point(c.x+cos(a)*r,c.y+sin(a)*r);
    }
    void read()
    {
        scanf("%lf %lf %lf",&c.x,&c.y,&r);
    }
};
double angle(Vector v)
{
    return atan2(v.y,v.x);
}

int getLineCircleIntersection(Line L,Circle C,vector<Point>& sol)//圆和直线相交
{
    double a=L.v.x,b=L.p.x-C.c.x,c=L.v.y,d=L.p.y-C.c.y;
    double e=a*a+c*c,f=2.0*(a*b+c*d),g=b*b+d*d-C.r*C.r;
    double delta=f*f-4.0*e*g;
    double t1,t2;
    if(sgn(delta)<0) return 0;
    if(sgn(delta)==0)
    {
        t1=t2=-f/(2*e);sol.push_back(L.point(t1));
        return 1;
    }
    t1=(-f-sqrt(delta))/(2.0*e),t2=(-f+sqrt(delta))/(2.0*e);
    sol.push_back(L.point(t1)),sol.push_back(L.point(t2));
    return 2;
}

int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol) //圆和圆相交
{
    double d=Length(C1.c-C2.c);
    if(sgn(d)==0)
    {
        if(sgn(C1.r-C2.r)==0)
            return -1; //重合
        return 0;
    }
    if(sgn(C1.r+C2.r-d)<0)
        return 0;
    if(sgn(fabs(C1.r-C2.r)-d )>0)
        return 0;

    double a=angle(C2.c-C1.c);
    double da=acos( (C1.r*C1.r+d*d-C2.r*C2.r)/ (2 * C1.r*d) );
    Point p1=C1.point(a-da),p2=C1.point(a+da);
    sol.push_back(p1);
    if(p1==p2)
        return 1;
    sol.push_back(p2);
    return 2;
}

int getTangents(Point p,Circle C, Vector* v)//过点p到圆c的切线,v[i]是第i条切线的向量
{
    Vector u=C.c-p;
    double dist=Length(u);
    if(dist<C.r) return 0;
    else if(sgn(dist-C.r)==0)
    {
        v[0]=Rotate(u,pi/2);
        return 1;
    }
    else
    {
        double ang=asin(C.r/dist);
        v[0]=Rotate(u,ang);
        v[1]=Rotate(u,-ang);
        return 2;
    }
}



//圆的公切线 返回切条条数 返回-1表示无数条切线
//a[i] 和 b[i]分别是第条切线在圆A,圆B上的切点
int getTangents(Circle A,Circle B,Point *a, Point *b)
{
    int cnt=0;
    if(A.r<B.r)
    {
        swap(A,B);swap(a,b);
    }
    double d2=(A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y);
    double rdiff=A.r-B.r;
    double rsum=A.r+B.r;
    if(sgn(d2-rdiff*rdiff)<0)
        return 0;

    double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);
    if(sgn(d2)==0&&sgn(A.r-B.r)==0)
        return -1;
    if(sgn(d2-rdiff*rdiff)==0)
    {
        a[cnt]=A.point(base),b[cnt]=B.point(base),cnt++;
        return 1;
    }

    double ang=acos((A.r-B.r) / sqrt(d2));
    a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang);cnt++;
    a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang);cnt++;
    if(sgn(d2-rsum*rsum)==0)
    {
        a[cnt]=A.point(base);b[cnt]=B.point(base+pi);cnt++;
    }
    else if(sgn(d2-rsum*rsum)>0)
    {
        double ang=acos( (A.r+B.r)/sqrt(d2) );
        a[cnt]=A.point(base+ang);b[cnt]=B.point(base+ang+pi);cnt++;
        a[cnt]=A.point(base-ang);b[cnt]=B.point(base-ang+pi);cnt++;
    }
    return cnt;
}

/*
凸包部分
---------------------------------------
---------------------------------------
*/


//判断点是否在多边形内部
int isPointInPolygon(Point p,Point *Poly,int n)
{
    int wn=0;
    for(int i=0;i<n;i++)
    {
        if(OnSegment(p,Poly[i],Poly[(i+1)%n]))
            return -1;//在边界上
        int k=sgn(Cross(Poly[(i+1)%n]-Poly[i],p-Poly[i]));
        int d1=sgn(Poly[i].y-p.y);
        int d2=sgn(Poly[(i+1)%n].y-p.y);
        if(k>0&&d1<=0&&d2>0) wn++;
        if(k<0&&d2<=0&&d1>0) wn--;
    }
    if(wn!=0) return 1;
    return 0;
}

//二维凸包扫描
int ConvexHull(Point *p,int n,Point *Poly)
{
    sort(p,p+n);
    int m=0;
    for(int i=0;i<n;i++)
    {
        while(m>1 && Cross(Poly[m-1]-Poly[m-2],p[i]-Poly[m-2] ) <= 0 ) m--;
        Poly[m++]=p[i];
    }
    int k=m;
    for(int i=n-2;i>=0;i--)
    {
        while(m>k &&  Cross(Poly[m-1]-Poly[m-2],p[i]-Poly[m-2]) <=0) m--;
        Poly[m++]=p[i];
    }
    if(n > 1) m--;
    return m;
}

/*

半平面交
-----------------------------------------------------
-----------------------------------------------------

*/

//判断点在有向直线左侧
bool OnLeft(Line L,Point p)
{
    return Cross(L.v,p-L.p) > 0;
}

//半平面交
int HalfplaneIntersection(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]=GetLineIntersection(q[last-1].p,q[last].p,
                                                     q[last-1].v,q[last].v);
    }
    while(first<last &&  !OnLeft(q[first],p[last-1])) last--;
    if(last-first <=1) return 0;
    p[last] =GetLineIntersection(q[last].p,q[first].p,
                                 q[last].v,q[first].v);
    int m=0;
    for(int i=first;i<=last;i++) Poly[m++]=p[i];
    return m;
}

Point Poly[110],Ps[110];
Line L[110];
Line L1[110];
bool solve(double k,int n)
{
    for(int i=0;i<n;i++)
    {
        Vector v=Rotate(L[i].v,pi/2);
        v=v/Length(v);
        L1[i]=L[i];
        L1[i].p=L[i].p+v*k;
    }
    return HalfplaneIntersection(L1,n,Ps);
}
int main()
{
    int n;
    while(cin>>n&&n)
    {
        for(int i=0;i<n;i++)
            Poly[i].read();
        for(int i=0;i<n;i++)
        {
            L[i].v=Poly[(i+1)%n]-Poly[i];
            L[i].p=Poly[i];
            L[i].ang=angle(L[i].v);
        }
        double l=0.0,r=1e7,mid;
        while(fabs(r-l)>eps)
        {
            mid=(l+r)/2;
            if(solve(mid,n))
                l=mid;
            else
                r=mid;
        }
        printf("%.5lf\n",mid);
    }
    return 0;
}


你可能感兴趣的:(ACM,uva,计算几何)