穿越七色虹

穿越七色虹

题意

大概是给出 7 个半圆的圆心和半径,人有一个高度, 人要从 \(0\)\(x_0\) 的位置,问最少加上多少才可以使这个队伍通过。

最小化答案考虑二分答案。

如何写 check 是本题的关键, 也是本题的难点。

首先有两点需要满足:

  • 人要站的下
  • 人要走得了
处理第一点

对于第一点, 看下图

黄色部分是可以通过的部分,提取出来发现这好像是一个三角形, 如下图:

\(o\) 表示圆心, \(r\) 表示半径, \(h\) 表示人的高度。

这个矩形满足了人站的下的条件。我们可以把这个半圆形转换成这样的一个矩形,即人可以活动的范围。

如何求这个矩形?

显然这是在一个三角形里面的, 现在是在知二求一,用勾股定理就好了。

什么?你不知道勾股定理?就是在一个直角三角形里面斜边的平方等于直角边平方之和。

处理第二点

考虑第二点,只用记录之前求的矩形的左端点和右端点,在判断一下是否包含了起点 \(0\) 和 终点 \(x_0\) 本题就结束了。

注意本题最好使用 for 约束循环次数。

code
#include <bits/stdc++.h>

using i64 = long long;

int main() {
	struct node {double x, r;};
	struct Node {double l, r;};
	
	double h, x0;
	std::cin >> h >> x0;
	
	std::vector<node> a(8);
	for (int i = 1; i <= 7; i++) {
		std::cin >> a[i].x >> a[i].r;
	}
	
	std::function<bool(node, node)> cmp = [&](node a, node b) {return a.x < b.x;}; 
	std::sort(a.begin() + 1, a.begin() + 8, cmp);
	
	std::function<double(double, double)> dis = [&](double a, double x) {return sqrt((a + x) * (a + x) - h * h);};
	std::function<double(double, double)> min = [&] (double a, double b) {return a < b ? a : b;};
	std::function<double(double, double)> max = [&] (double a, double b) {return a > b ? a : b;};
	
	std::function<bool(double)> check = [&](double x) {
		std::vector<Node> b(10); 
		for (int i = 1; i <= 7; i++) {
			if (a[i].r + x >= h) {
				b[i].l = a[i].x - dis(a[i].r, x);
				b[i].r = a[i].x + dis(a[i].r, x);
			}
		}
		double mx = b[1].r, mn = b[1].l;
		for (int i = 2; i <= 7; i++) {
			if (b[i].l <= mx) {
				mn = min(mn, b[i].l);
				mx = max(mx, b[i].r);
			}
		}
		return mn <= 0 && mx >= x0;
	}; 
	
	double l = 0, r = x0;
	for (int i = 1; i <= 100; i++) {
		double mid = (l + r) / 2; 
		if (check(mid)) r = mid;
		else l = mid;
	}
	
	std::cout << std::fixed << std::setprecision(2) << l << std::endl;
	

	return 0;
}

posted @ 2022-02-08 19:06  落花月朦胧  阅读(85)  评论(1编辑  收藏  举报