bzoj1038: [ZJOI2008]瞭望塔
http://www.lydsy.com/JudgeOnline/problem.php?id=1038
本题可以使用三分法
将点按横坐标排好序后
对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数
感性理解单峰就是
瞭望塔建的靠左,为了能看到右边的,要高一点
瞭望塔建的靠右,为了能看到左边的,要高一点
所以
枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小
#include<cmath> #include<cstdio> #include<algorithm> using namespace std; #define N 301 const double eps=1e-7; int n; struct POINT { double x,y; }e[N]; struct LINE { double k,b; bool exit; }l[N]; bool cmp(POINT p,POINT q) { return p.x<q.x; } double cal(double x,double y) { double tmp=0; for(int i=1;i<n;++i) { if(!l[i].exit) continue; tmp=fmax(tmp,l[i].k*x+l[i].b-y); } return tmp; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lf",&e[i].x); for(int i=1;i<=n;++i) scanf("%lf",&e[i].y); sort(e+1,e+n+1,cmp); for(int i=1;i<n;++i) { if(fabs(e[i].x-e[i+1].x)<eps) continue; l[i].k=(e[i].y-e[i+1].y)/(e[i].x-e[i+1].x); l[i].b=e[i].y-e[i].x*l[i].k; l[i].exit=true; } double L,R,mid1,mid2; int T; double ans=1e20; for(int i=1;i<n;++i) { if(!l[i].exit) continue; T=100; L=e[i].x; R=e[i+1].x; while(T--) { mid1=L+(R-L)/3; mid2=R-(R-L)/3; if(cal(mid1,l[i].k*mid1+l[i].b)<cal(mid2,l[i].k*mid2+l[i].b)) R=mid2; else L=mid1; } ans=fmin(ans,cal(mid1,l[i].k*mid1+l[i].b)); } printf("%.3lf",ans); }
1038: [ZJOI2008]瞭望塔
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2658 Solved: 1084
[Submit][Status][Discuss]
Description
致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。我们
将H村抽象为一维的轮廓。如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描
述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可
以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长
希望建造的塔高度尽可能小。请你写一个程序,帮助dadzhi村长计算塔的最小高度。
Input
第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1
~ yn。
Output
仅包含一个实数,为塔的最小高度,精确到小数点后三位。
Sample Input
【输入样例一】
6
1 2 4 5 6 7
1 2 2 4 2 1
【输入样例二】
4
10 20 49 59
0 10 10 0
6
1 2 4 5 6 7
1 2 2 4 2 1
【输入样例二】
4
10 20 49 59
0 10 10 0
Sample Output
【输出样例一】
1.000
【输出样例二】
14.500
1.000
【输出样例二】
14.500
HINT
N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。