题目描述
致力于建设全国示范和谐小村庄的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仅包含一个实数,为塔的最小高度,精确到小数点后三位。
输入输出样例
说明
对于60%的数据, N ≤ 60;
对于100%的数据, N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。
首先,塔i顶的位置属于一个区域:有所有相邻的两个点确定直线的组成的凸包
然后出现了许多分段的一次函数,断电是地面上的焦点和凸包的拐,然后最值从端点出取得
因此枚举地面上的焦点和凸包的拐点都算一遍就行了,因为这题的数据比较小,也可以枚举每两条直线的焦点算一遍qwq
然后还有第二种做法就是,考虑地面上的每一个线段,有一个理解是:
瞭望塔建的靠左,为了能看到右边的,要高一点
瞭望塔建的靠右,为了能看到左边的,要高一点
对于任意相意两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数
三分就完事了
不用(hui)证明 - -
给出第一个做法的码:
1 #include<iostream>
2 #include<algorithm>
3 #include<cstring>
4 #include<cstdio>
5 using namespace std;
6 typedef double db;
7 const int N=305;
8 const db inf=99999999999.0;
9 int n;
10 db ax[N],ay[N];
11 struct LINE{
12 db k,b; //y=kx+b
13 }ln[N];
14 db ans=inf;
15 db sol(db x){ //计算特定横坐标的最小瞭望塔高度
16 db res=0;
17 for(int i=1;i<n;i++)
18 res=max(res,ln[i].k*x+ln[i].b);
19 return res;
20 }
21 int main(){
22 scanf("%d",&n);
23 for(int i=1;i<=n;i++)
24 scanf("%lf",&ax[i]);
25 for(int i=1;i<=n;i++)
26 scanf("%lf",&ay[i]);
27 for(int i=1;i<n;i++){
28 ln[i].k=(ay[i]-ay[i+1])/(ax[i]-ax[i+1]);
29 ln[i].b=ay[i]-ln[i].k*ax[i];
30 }
31 for(int i=1;i<=n;i++)
32 ans=min(ans,sol(ax[i])-ay[i]); //先枚举每个端点
33 for(int i=1;i<n;i++)
34 for(int j=i+1;j<n;j++){
35 db x=(ln[i].b-ln[j].b)/(ln[j].k-ln[i].k); //求两直线的交点
36 for(int k=1;k<n;k++)
37 if(ax[k]<=x&&x<=ax[k+1])
38 ans=min(ans,sol(x)-ln[k].k*x-ln[k].b); //最小化答案
39 }
40 printf("%.3lf
",ans);
41 return 0;
42 }