牛客2021暑假多校训练(2) F - 计算几何 两球之交 + 定比分点 + 阿波罗尼斯圆性质
Girlfriend
https://ac.nowcoder.com/acm/contest/11253/F
题意
组询问,每次给定空间中的四个定点
,以及两个常数
,动点
制约于
.求
构成的几何体的体积交,答案精度误差不得超过
.
制约
,保证
互异。
思路
高中数学复习:对于
两定点,动点
满足
,则有:
是一条直线
是 一个圆,称作阿波罗尼斯圆,简称阿氏圆
证明:设
.以
中点为坐标原点,
作为
轴建立平面直角坐标系,则
.设P
,由
,有
,两边平方,化简得
是
的中垂线
而在三维空间中,其形态自然是一个球。这实际上是阿氏圆推出来的,后面的两个球方程该怎么搞呢?按照上面的建系的方式来推,避免不了要化简复杂的算式,所以下面要介绍一个公式(实际上也是数学手的第一直觉):定比分点公式
多么优美的算式
由此,我们就可以确定所在点的最小值了(取等号时刻的位置),那么最远处该怎么算呢?我门取与之相对称的位置(负方向的等号)即可:
。圆心在两点的中点处,半径则是两点距离的一半,剩下只需要判断相离(相切)、内含(外含)与相交的情况了
套板子。
模板+代码
#include <bits/stdc++.h>
using namespace std;
static const double PI = acos(-1.0);
struct point {
double x,y,z;
point(double _x = .0, double _y = .0,double _z = .0)
: x(_x), y(_y), z(_z) { }
point operator -(const point &b)const { return point(x - b.x, y - b.y, z - b.z); }
point operator +(const point &b)const { return point(x + b.x, y + b.y, z + b.z); }
point operator *(const double &k)const { return point(x * k, y * k,z * k); }
point operator /(const double &k)const { return point(x / k, y / k, z / k); }
double operator *(const point &b)const { return x * b.x + y * b.y + z * b.z; }
friend point operator*(double x, point p) { return p * x; }
};
double dist(point p1, point p2) {return sqrt((p1 - p2) * (p1 - p2)); }
struct sphere {
point center;
double r;
sphere(point _center = point(), double _r = 1.)
: center(_center), r(_r) { }
};
void SphereInterVS(sphere a, sphere b,double &v,double &s) {
double d = dist(a.center, b.center);
double t = (d * d + a.r * a.r - b.r * b.r) / (2. * d);
double h = sqrt((a.r * a.r) - (t * t)) * 2;
double angle_a = 2 * acos((a.r*a.r + d*d - b.r*b.r) / (2. * a.r*d));
double angle_b = 2 * acos((b.r*b.r + d*d - a.r*a.r) / (2. * b.r*d));
double l1 = ((a.r * a.r - b.r * b.r) / d + d) / 2;
double l2 = d - l1;
double x1 = a.r - l1, x2 = b.r - l2;
double v1 = PI * x1 * x1 * (a.r - x1 / 3);
double v2 = PI * x2 * x2 * (b.r - x2 / 3);
v = v1 + v2;
double s1 = PI * a.r * x1;
double s2 = PI * a.r * x2;
s = 4. * PI * (a.r*a.r + b.r*b.r) - s1 - s2;
} sphere set_sphere(point a, point b, double k) {
point t1(1. / (1 + k) * a + 1. * k / (1 + k) * b);
point t2(1. * k / (k - 1) * b - 1. / (k - 1) * a);
return sphere((t1 + t2) / 2., dist(t1, t2) / 2.);
}
int main() {
// ios::sync_with_stdio(false), cin.tie(nullptr);
int tt; cin >> tt; while (tt --) {
sphere a, b;
int k1, k2, x1, x2, y1, y2, z1, z2, x3, x4, y3, y4, z3, z4;
double v = 0., s = .0;
cin >> x1 >> y1 >> z1; point p1(x1, y1, z1);
cin >> x2 >> y2 >> z2; point p2(x2, y2, z2);
cin >> x3 >> y3 >> z3; point p3(x3, y3, z3);
cin >> x4 >> y4 >> z4; point p4(x4, y4, z4);
cin >> k1 >> k2;
a = set_sphere(p1, p2, k1);
b = set_sphere(p3, p4, k2);
double ans = .0, dis = dist(a.center, b.center);
if(dis >= a.r + b.r) { // 两球相离
ans = .0;
} else if(dis + min(a.r, b.r) <= max(a.r, b.r)) { // 两球内含
ans = 4. / 3. * PI * min(a.r, b.r) * min(a.r, b.r) * min(a.r, b.r);
} else {
SphereInterVS(a, b, v, s);
ans = v;
}
printf("%.10f\n", ans);
}
return 0;
}
顺丰集团工作强度 276人发布
查看6道真题和解析