P2600 [ZJOI2008]瞭望塔

题目描述

致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。

我们将H村抽象为一维的轮廓。如下图所示

P2600 [ZJOI2008]瞭望塔_第1张图片

我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。

请你写一个程序,帮助dadzhi村长计算塔的最小高度。

输入格式

输入文件tower.in第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

输出格式

输出文件tower.out仅包含一个实数,为塔的最小高度,精确到小数点后三位。

输入输出样例

输入 #1

6

1 2 4 5 6 7

1 2 2 4 2 1

输出 #1

1.000

说明/提示

对于60%的数据, N ≤ 60;

对于100%的数据, N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。

半平面交练习题 , 注意判断有没有在右边时 , 想清楚在线上的要不要

#include
#include
#include
#include
using namespace std;
const int N = 350;
const double eps = 1e-7;
int n , head , tail;
struct point{
    double x , y;
    point(double X = 0.0 , double Y = 0.0): x(X) , y(Y) {}
    bool operator < (const point &A) const { return x < A.x; }
    friend point operator - (point A , point B) { return point(A.x - B.x , A.y - B.y); }
    friend point operator * (point A , double B) {return point(A.x * B , A.y * B); }
    friend point operator + (point A , point B) { return point(A.x + B.x , A.y + B.y); }
} a[N] , p[N];

struct Line{
    point v , p;
    double an;
    Line(point V = point(0,0), point P = point(0,0)) : v(V) , p(P) { an = 0.0;}
    bool operator < (const Line A) const { return an < A.an; }
} l[N] , sta[N] , li[N];
inline int dcmp(double A) { return fabs(A) < eps ? 0 : (A < eps ? -1 : 1); }
inline double accross(point A , point B) { return A.x * B.y - A.y * B.x; }
inline bool onright(point A , Line B) { return dcmp(accross(A - B.p , B.v)) > 0; }
inline point meetline(Line A , Line B)
{
    if(dcmp(accross(A.v , B.v)) == 0) return (point){0 , 0};
    point k = A.p - B.p;
    return A.p + A.v * (accross(B.v , k) / accross(A.v , B.v));
}

int Get_ans(int n)
{
    sort(l + 1 , l + 1 + n); sta[head = tail = 1] = l[1];
    for(int i = 2 ; i <= n ; ++i)
    {
        while(head < tail && onright(p[tail-1] , l[i])) tail--;
        while(head < tail && onright(p[head] , l[i])) head++;
        sta[++tail] = l[i];
        if(dcmp(accross(sta[tail].v , sta[tail-1].v)) == 0)
        {
            tail--;
            if(onright(sta[tail].p , l[i])) sta[tail] = l[i];
        }
        if(head < tail) p[tail-1] = meetline(sta[tail] , sta[tail-1]);
    }
    while(head < tail && onright(p[tail-1] , sta[head])) tail--;
    for(int i = head ; i <= tail ; ++i) p[i-head+1] = p[i] , sta[i-head+1] = sta[i]; 
    return tail - head;
}

double calc(point p , point a , point b)
{
    double K = (b.y - a.y) / (b.x - a.x);
    double B = a.y - K * a.x;
    return fabs(p.x * K + B - p.y);
}

int main()
{
    scanf("%d" , &n);
    for(int i = 1 ; i <= n ; ++i) scanf("%lf" , &a[i].x);
    for(int i = 1 ; i <= n ; ++i) scanf("%lf" , &a[i].y);
    sort(a + 1 , a + 1 + n);
    for(int i = 1 ; i < n ; ++i) l[i].v = a[i+1] - a[i] , l[i].p = a[i] , l[i].an = atan2(l[i].v.y , l[i].v.x) , li[i] = l[i];
    int cnt = Get_ans(n - 1);
    // cout << cnt << endl;
    int l = 1 , r = 1; double ans = 1e15;
    while(l <= cnt && r <= n)
    {
        if(p[l].x < a[r].x)
        ans = min(ans , p[l].y - meetline(li[r-1] , Line(point(0,1) , p[l])).y) , l++;
        else
        ans = min(ans , meetline(sta[l] , Line(point(0,1) , a[r])).y - a[r].y) , r++;
    }
    while(l <= cnt) ans = min(ans , p[l].y - meetline(li[r-1] , Line(point(0,1) , p[l])).y) , l++;
    while(r <=  n)  ans = min(ans , meetline(sta[l] , Line(point(0,1) , a[r])).y - a[r].y) , r++;
    printf("%.3f" , ans);
    return 0;
}
/*
4
10 20 49 59
0 10 10 0
*/

你可能感兴趣的:(P2600 [ZJOI2008]瞭望塔)