P1663 山

写在前面

简单的二分答案,稍微加点数学计算,很有意思。

算法思路

二分答案可行的原因:答案具有单调性。

这道题目中证明一下:首先无限高显然是能看到任何一个点的,且山的每一条边都是对答案的一个限制,因此位置越低可能受到的限制就越多,能看到所有位置的机会就越少,直至出现不可行的答案。

因此只需要统计出每一对相邻的折点,求解出这两点所在的直线方程。随后二分答案。

对于每个可能二分到的答案,每条直线的限制都会与其构成一个一元不等式,将所有的不等式组成不等式组,判断其是否有解。

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;
}
posted @ 2020-10-25 10:47  zimujun  阅读(82)  评论(0编辑  收藏  举报