瞭望塔

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

4
 10 20 49 59
 0 10 10 0

Sample Output

14.500

HINT

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

Solution

首先,如果我们确定了一个点的话,显然是可以Check的。

对于 每一个点连向这个点连线 必须是要逆时针方向的。

那么如果有一个横坐标了,我们就可以二分答案了。怎么确定这个横坐标呢?

乍一看,数据这么小:当然是模拟退火啦!上一波退火美滋滋。٩(๑>◡<๑)۶

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long s64;

const int ONE = 1005;
const double eps = 1e-4;

int n;
double from, to;
double Ans = 1e20;

struct power
{
double x, y;
}a[ONE];

int get()
{
int res,Q=1; char c;
while( (c=getchar())<48 || c>57)
if(c=='-')Q=-1;
if(Q) res=c-48;
while((c=getchar())>=48 && c<=57)
res=res*10+c-48;
return res*Q;
}

int PD(double a, double b)
{
if(fabs(a - b) <= eps) return 0;
if(a > b) return 1;
return -1;
}

double Gety(double x)
{
for(int i = 2; i <= n; i++)
if(PD(a[i-1].x, x) <= 0 && PD(x, a[i].x) <= 0)
{
double k = (a[i].y - a[i-1].y) / (a[i].x - a[i-1].x);
double b = a[i-1].y;
return k * (x - a[i-1].x) + b;
}
}

double Cross(power a, power b, power c) {return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);}
int Check(power A)
{
for(int i = 2; i <= n; i++)
if(PD(Cross(a[i-1], a[i], A), 0) < 0) return 0;
return 1;
}

double Judge(double x)
{
double l = 0, r = 1e10, res;
double y = Gety(x);
while(l < r - 0.0001)
{
double mid = (l + r) / 2;
if(Check( (power){x, y + mid} )) r = mid;
else l = mid;
}
if(Check( (power){x, y + l} )) res = l; else res = r;
Ans = min(Ans, res);
return res;
}

double Random() {return (rand()%1000) / 1000.00;}
void SA(double T)
{
double Now = (from + to) / 2, A;
Judge(Now);
while(T >= 0.0001)
{
A = Now + T * (Random() * 2 - 1);
if(!(from <= A && A <= to)) continue;
double dE = Judge(Now) - Judge(A);
if(dE > 0 || Random() <= exp(dE / T))
Now = A;
T *= 0.993;
}

for(double i = -1; i <= 1; i += 0.001)
Judge(Now + i);
}

int main()
{
n = get();
for(int i = 1; i <= n; i++) scanf("%lf", &a[i].x);
for(int i = 1; i <= n; i++) scanf("%lf", &a[i].y);


from = a[1].x; to = a[n].x;
SA(to - from);

printf("%.3lf", Ans);
}