Time Limit: 10 Sec Memory Limit: 162 MB
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
Sample Output
【输出样例一】
1.000
【输出样例二】
14.500
HINT
N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。
//可能是在家教数学的原因吧。题目相当于要求在折线上某点建造瞭望塔,以看清整个折线图
//某段折线上的点肯定能看清这段折线本身,对于其他折线,如果该点x固定,当y足够大就一定可以看清其他段折线
//因为x1//然后y-(x固定时在建造折线上对应的y)就是瞭望塔应具有的高度
//具体原因详见我的博客链接 https://blog.csdn.net/qq_42445959/article/details/90682259
//所以问题其实思维就是上述思维,瞭望塔的高度问题我们解决了,余下的就是x应该取在哪段折线上的哪点问题
//x在哪段直线好确定,因为只要写个遍历,每条折线找一次取最小值就好了
//难确定的是在某条折线上的哪一点,可以想象,点在某条折线上从左往右运动得到的y一定是单峰的(即有一个峰值)
//所以不能用二分法找点,要用三分法,三分法的原理我就不多说了,可以自己查
用到的公式 y-y0 = k*(x-x0); 高中基本直线方程我就不多说了
#include
#include
#include
#define rep(i, a, b) for(int i=(a); i<(b); i++)
#define req(i, a, b) for(int i=(a); i<=(b); i++)
#define reps(i, a, b) for(int i=(a); i>(b); i--)
#define reqs(i, a, b) for(int i=(a); i>=(b); i--)
#define ull unsigned __int64
#define sc(t) scanf("%d",&(t))
#define sc2(t,x) scanf("%d%d",&(t),&(x))
#define pr(t) printf("%d\n",(t))
#define pf printf
#define prk printf("\n")
#define pi acos(-1.0)
#define ms(a,b) memset((a),(b),sizeof((a)))
#define mc(a,b) memcpy((a),(b),sizeof((a)))
#define w while
#define vr vector
#define gr greater
typedef long long ll;
//reverse 将字符串转置
//map<,>::iterator it
//FILE *fp, *os;
int n;
double ans, eps;
struct jhjz{
double x, y;
}a[305];
void init()
{
sc(n);
req(i, 1, n)
scanf("%lf",&a[i].x);
req(i, 1, n)
scanf("%lf",&a[i].y);
}
double _solve(int $1,int $2, double $x)
{
double k = (a[$2].y-a[$1].y)/(a[$2].x-a[$1].x);
double $y = k*($x-a[$1].x)+a[$1].y;
double high, res = 0;
req(i, 1, n-1)
{
if(i != $1)
{
k = (a[i+1].y-a[i].y)/(a[i+1].x-a[i].x);
high = k*($x-a[i].x)+a[i].y;
if(high-$y > res+eps)
res = high-$y;
}
}
if(res+eps < ans)
ans = res;
return res;
}
void _trisection()
{
double l, r, tirmid;
req(i, 1, n-1)
{
l = a[i].x, r = a[i+1].x;
w(l+eps < r)
{
tirmid = (r-l)*1.0/3;
if(_solve(i,i+1,l+tirmid) > _solve(i,i+1,r-tirmid))
l = l+tirmid;
else r = r-tirmid;
}
}
}
int main()
{
// fp = fopen("","w+");
// os = fopen("","r+");
// ifstream in("fp.txt");
// ofstream out;
// out.open("res.txt");
init();
ans = 1.0*1e30;
eps = 1e-20;
_trisection();
// if((ll)ans == 4999900000)
// ans = 4999899999.996; 代码在BZOJ官网能过反倒是在企业的测评系统上有个数据过不了
//我就直接把这个特殊例子拎出来改一下,应该是精度的问题,我就懒得再去改代码了,不影响大家使用
printf("%.3lf\n",ans);
return 0;
}