ZJOI 2008 瞭望塔 半平面交

来源:互联网 发布:英文翻译什么软件好 编辑:程序博客网 时间:2024/05/17 20:30

题意:

给出一个以n个点为轮廓的村庄,在村庄任意位置放一个瞭望塔,使瞭望塔能看到村庄的所有位置,求瞭望塔最低高度。


思路:

考虑轮廓的每一条边,要看到这条边就必须在这条边以上的一个半平面内,因此求半平面交即可,样例图:



不妨将半平面交与地面上的直线看成分段函数,分别为f(x)与g(x),则所求即为h(x) = f(x) - g(x)的最小值,由于f(x)与g(x)均为一次分段函数,故h(x)也是一次分段函数,其最值仅可能在每一段的端点处取到。


注意:

1)输入的坐标为整数,注意转为double

2)叉积代表有向面积,写的时候要想清楚方向


由于是第一次写半平面交,根据老人家的模板写的,其实由于本题的特殊性可以写得更简单(例如直线可用斜截式),但这样的写法更具一般性,代码:

#include <cstdio>#include <algorithm>#include <cmath>#define For(i,j,k) for(int i = j;i <= k;i++)#define dcmp(x) (x > eps ? 1 : (x < -eps ? -1 : 0))using namespace std;const int N = 310;const double eps = 1e-8;struct Point{    double x, y;    Point(){}    Point(double X, double Y):x(X), y(Y){}    bool operator < (const Point& A) const{        return x < A.x;    }};typedef Point Vector;Vector operator - (const Point &A, const Point &B){return Vector(A.x - B.x, A.y - B.y);}Point operator + (const Point &A, const Vector &V){return Point(A.x + V.x, A.y + V.y);}Vector operator * (const Vector &V, double k){return Vector(V.x * k, V.y * k);}double Cross(const Vector &A, const Vector &B){return A.x * B.y - A.y * B.x;}struct Line{    Point P;    Vector v;    double ang;    Line(){}    Line(const Point& A, const Point& B){        v = B - A;        P = A;        ang = atan2(v.y, v.x);    }    bool operator <(const Line& A) const{        return ang < A.ang;    }};Point Intersection(Line& A, Line& B){    Vector v = A.P - B.P;    double s = Cross(B.v, v) / Cross(A.v, B.v);    return A.P + A.v * s;}bool Onleft(Line& L, Point& P){    return Cross(L.v, P - L.P) > 0;}int n, m;Line q[N], L[N];Point p[N], land[N];void HalfplaneIntersection(){    int l = 1, r = 1;    sort(L + 1, L + n + 1);    q[l] = L[1];    For(i,2,n){        while(l < r && !Onleft(L[i], p[r-1])) r--;        while(l < r && !Onleft(L[i], p[l])) l++;        q[++r] = L[i];        if(l < r && !dcmp(Cross(q[r].v, q[r-1].v))){            r--;            if(Onleft(q[r], L[i].P)) q[r] = L[i];        }        if(l < r) p[r-1] = Intersection(q[r-1], q[r]);    }    while(l < r && !Onleft(q[l], p[r-1])) r--;    p[r] = Intersection(q[r], q[l]);    For(i,l,r) p[i - l + 1] = p[i];    m = r - l + 1;}int x[N], y[N];int main(){    scanf("%d", &n);    For(i,1,n) scanf("%d", &x[i]);    For(i,1,n) scanf("%d", &y[i]), land[i] = Point(x[i], y[i]);    For(i,1,n-1) L[i] = Line(land[i], land[i+1]);    L[n] = Line(Point(1e12, 1e12), Point(-1e12, 1e12));    HalfplaneIntersection();    sort(p + 1, p + m + 1);    double Ans = 1e12;    For(i,1,n)        For(j,1,m-1)            if(dcmp(x[i] - p[j].x) >= 0 && dcmp(x[i] - p[j+1].x) <= 0){                Ans = min(Ans, p[j].y + (p[j+1].y - p[j].y) / (p[j+1].x - p[j].x) * (x[i] - p[j].x) - y[i]);                break;            }    For(j,1,m)        For(i,1,n-1)            if(dcmp(p[j].x - x[i]) >= 0 && dcmp(p[j].x - x[i+1]) <= 0){                Ans = min(Ans, p[j].y - (1.0 * y[i] + 1.0 * (y[i+1] - y[i]) / (x[i+1] - x[i]) * (p[j].x - x[i])));                break;            }    printf("%.3lf\n", Ans);    return 0;}



1 0
原创粉丝点击