UVALive 3890 Most Distant Point from the Sea(凸包最大内接园)

一个n个点的凸多边形,求多边形中离多边形边界最远的距离。实际上就是求凸包最大内接圆的半径。

利用半平面交求解,每次二分枚举半径d,然后将凸包每条边所代表的半平面沿其垂直单位法向量平移d,看所有平移后的半平面的交集是否为空。

 

#include<algorithm>

#include<iostream>

#include<cstring>

#include<cstdlib>

#include<fstream>

#include<sstream>

#include<bitset>

#include<vector>

#include<string>

#include<cstdio>

#include<cmath>

#include<stack>

#include<queue>

#include<stack>

#include<map>

#include<set>

#define FF(i, a, b) for(int i=a; i<b; i++)

#define FD(i, a, b) for(int i=a; i>=b; i--)

#define REP(i, n) for(int i=0; i<n; i++)

#define CLR(a, b) memset(a, b, sizeof(a))

#define debug puts("**debug**")

#define LL long long

#define PB push_back

#define eps 1e-10

using namespace std;



struct Point

{

    double x, y;

    Point (double x=0, double y=0):x(x), y(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 p) { return Vector(A.x*p, A.y*p); }

Vector operator / (Vector A, double p) { return Vector(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);

}



int dcmp(double x)

{

    if(fabs(x) < eps) return 0;

    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 Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }

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

double Angel(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(Vector A, Vector B, Vector C) { return Cross(B-A, C-A); }

Vector Normal(Vector a) //a向量的垂直法向量

{

     return Vector(-a.y/Length(a), a.x/Length(a));

}



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;

    }

};



//点p在半平面的左边

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;

}



const int maxn = 200;

Point p[maxn], poly[maxn];

Line L[maxn];

Vector v[maxn], v2[maxn];

int n;



//半平面交

Point pp[maxn];

Line qq[maxn];

int HalfplaneIntersection(Line* L, int n, Point* poly)

{

    sort(L, L+n);

    int first, last;



    qq[first=last=0] = L[0];

    FF(i, 1, n)

    {

        while(first < last && !onLeft(L[i], pp[last-1])) last--;

        while(first < last && !onLeft(L[i], pp[first])) first++;

        qq[++last] = L[i];

        if(fabs(Cross(qq[last].v, qq[last-1].v)) < eps)

        {

            last--;

            if(onLeft(qq[last], L[i].p)) qq[last] = L[i];

        }

        if(first < last) pp[last-1] = GetIntersection(qq[last-1], qq[last]);

    }

    while(first < last && !onLeft(qq[first], pp[last-1])) last--;

    if(last-first <= 1) return 0;

    pp[last] = GetIntersection(qq[last], qq[first]);



    int m = 0;

    FF(i, first, last+1) poly[m++] = pp[i];

    return m;

}





int main()

{

    while(scanf("%d", &n), n)

    {

        REP(i, n) scanf("%lf%lf", &p[i].x, &p[i].y);

        REP(i, n)

        {

            v[i] = p[(i+1)%n]-p[i];

            v2[i] = Normal(v[i]);

        }

        double l=0, r=20000, mid;

        while(r - l > eps)

        {

            mid = (l+r) / 2.0;

            REP(i, n) L[i] = Line(p[i]+v2[i]*mid, v[i]);

            int m = HalfplaneIntersection(L, n, poly);

            if(!m) r=mid; else l=mid;

        }

        printf("%.6f\n", l);

    }

    return 0;

}


 

 

你可能感兴趣的:(live)