题目描述
致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。
我们将H村抽象为一维的轮廓。如下图所示
我们可以用一条山的上方轮廓折线(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<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
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
*/