三分
首先三维变二维
L这条线必定和某一
个给定的点擦边,也就是经过那个点,我们假设它经过P(a, b), 并且L的斜率
为K(K < 0),那么L的方程就可以表示为 L: y = K * (x - a) + b,则H和R就
可以利用这个方程表示出来:
H = -a * K + b;
R = -b / K + a;
那么所求的圆锥的体积就是:
V = pi*H*R^2 = pi * (-a * K + b) * (-b / K + a) ^ 2
容易得到V(K)这个函数的导数:
V'(K) = - pi * (aK^2 + 2bK) * (aK - b)^2 / K^2
影响这个导数的正负性的唯一条件是 -(aK^2 + 2bK)
当-2b/a < K < 0时V'(K)大于零,也就是V的值是随着K递增的。
当K < -2b/a时V'(K)小于零,也就是V的值是随着K递减的。
于是可以得出一个结论,当K = -2b/a 时V取得最小值。
于是我们知道了V的单峰性,然后就可以通过枚举半径R,因为R对于V具有单谷
性,所以枚举R的时候可以采用三分。每次通过三分R找到最小的H,这个过程可
以通过枚举每个点,找到最大的极角alpha,R*tan(alpha)就是H了。
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <iterator>
#include <cmath>
#include <deque>
#include <stack>
#include <cctype>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef long double ld;
const int N = 10;
const int INF = 0xfffffff;
const double EPS = 1e-8;
const ll MOD = 1e9 + 7;
const ld PI = acos (-1.0);
#define INFL 0x7fffffffffffffffLL
#define met(a, b) memset(a, b, sizeof(a))
#define rep(c, a, b) for (int c = a; c < b; c++)
#define nre(c, a, b) for (int c = a; c > b; c--)
#define put(a) cout << setiosflags(ios::fixed) << setprecision(a)
struct point
{
double x, y, z, r;
};
vector <point> a;
double cot (double R);
int main ()
{
int n, t;
scanf ("%d", &t);
while (t--)
{
scanf ("%d", &n);
a.clear();
double ll = 0;
rep (i, 0, n)
{
double tx, ty, tz;
scanf ("%lf%lf%lf", &tx, &ty, &tz);
a.push_back ({tx, ty, tz, sqrt(tx*tx+ty*ty)});
ll = max (ll, sqrt(tx*tx+ty*ty));
}
double l = ll, r = ll*3, lm, rm;
while (r - l > EPS)
{
lm = (l + r) / 2;
rm = (lm + r) / 2;
if (cot(lm) * lm * lm < cot(rm) * rm * rm) r = rm;
else l = lm;
}
printf ("%.3lf %.3lf\n", cot(lm), lm);
}
return 0;
}
double cot (double R)
{
double h = 0;
rep (i, 0, a.size())
h = max (a[i].z / (R - a[i].r), h);
return h * R;
}
cin居然超时 用流读入加速也不行 看来流读入加速真的不给力啊