写在前面
简单的二分答案,稍微加点数学计算,很有意思。
算法思路
二分答案可行的原因:答案具有单调性。
这道题目中证明一下:首先无限高显然是能看到任何一个点的,且山的每一条边都是对答案的一个限制,因此位置越低可能受到的限制就越多,能看到所有位置的机会就越少,直至出现不可行的答案。
因此只需要统计出每一对相邻的折点,求解出这两点所在的直线方程。随后二分答案。
对于每个可能二分到的答案,每条直线的限制都会与其构成一个一元不等式,将所有的不等式组成不等式组,判断其是否有解。
Code
#include<bits/stdc++.h>
#define LF double
const int Maxn = 5e3 + 5;
const LF eps = 1e-2;
int n, x5, y5, x6, y6;
double k[Maxn], b[Maxn];
int cnt = 0;
void solve(int x3, int y3, int x4, int y4) {
cnt++;
k[cnt] = 1.000 * (y3 - y4) / (x3 - x4);
b[cnt] = 1.000 * y3 - 1.000 * k[cnt] * x3;
}
using namespace std;
inline int read() {
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '- ') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
bool check(LF h) {
LF lf = 0, rt = (LF)x6;
for(register int i = 1; i <= cnt; ++i) {
if(k[i] > 0) rt = min(rt, (h - b[i]) / k[i]);
else lf = max(lf, (h - b[i]) / k[i]);
}
return lf <= rt;
}
int main() {
n = read();
x5 = read(); y5 = read();
for(register int i = 1; i < n; ++i) {
x6 = read(); y6 = read();
solve(x5, y5, x6, y6);
x5 = x6; y5 = y6;
}
LF l = 0, r = 1000000, mid, ans;
while((l <= r) && (r - l > eps)) {
mid = (l + r) / 2;
if(check(mid)) {
ans = mid;
r = mid - eps;
}
else {
l = mid + eps;
}
}
printf("%.2lf", ans);
return 0;
}