穿越七色虹
穿越七色虹
题意
大概是给出 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;
}