题目大意
如图:
给定
w
,
g
,
r
,
h
w, g, r, h
w,g,r,h,求 Cable 的最小值和最大值,要满足中间点的高度不小于
r
r
r。
解题思路
最小值很简单,根据两边之和大于第三边,就是求两个杆顶点连线的长度。
难点是求最大值,这里的方法是三分。
要求的长度设为 f ( x ) f(x) f(x),则 f ( x ) = x 2 + ( g − r ) r + ( w − x ) 2 + ( h − r ) 2 f(x) =\sqrt {x^2+(g-r)^r}+\sqrt{(w-x)^2+(h-r)^2} f(x)=x2+(g−r)r+(w−x)2+(h−r)2,其中 x ∈ ( 0 , w ) x\in(0,w) x∈(0,w)。
f ( x ) f(x) f(x) 是一个先递减再递增的函数,则用三分求解。
参考代码
#include<stdio.h>
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<deque>
#include<map>
#include<unordered_map>
#include<set>
#include<stack>
//#define LOCAL //提交时一定注释
#define VI vector<int>
#define eps 1e-6
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
typedef long long LL;
typedef double db;
const int inf = 0x3f3f3f3f;
const LL INF = 1e18;
const int N = 1e3 + 10;
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
inline int readint() {int x; scanf("%d", &x); return x;}
db w, g, r, h;
db calmin() {
return sqrt((h - g) * (h - g) + w * w);
}
db calma(db x) {
return sqrt(x * x + (g - r) * (g - r)) + sqrt((w - x) * (w - x) + (h - r) * (h - r));
}
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int t = readint();
while (t--) {
cin >> w >> g >> h >> r;
db min = calmin();
db l = 0, r = w;
db mid1, mid2;
while (r - l > eps) {
db k = (r - l) / 3.0;
mid1 = l + k;
mid2 = r - k;
if (calma(mid1) < calma(mid2)) r = mid2;
else l = mid1;
}
db ma = calma(l);
printf("%.8f %.8f\n", min, ma);
}
return 0;
}