1 条题解
-
0
题意分析
题目要求计算激光在多个反射球体间传播后的最后一个反射点。激光从原点沿方向射出,每次反射遵循入射角等于反射角的规则。需模拟光线在球体间的反射过程,直到光线不再与任何球体相交。每个球体由球心坐标和半径定义,且任意两球表面间距≥0.1,原点距任何球体表面≥0.1。
解题思路
代码通过向量运算和几何关系模拟反射过程:1)定义三维向量类处理点和方向;2)每次计算光线与所有球体的交点,选择最近的有效交点作为反射点;3)通过对称变换计算反射后的方向向量;4)重复上述过程直至光线不再与任何球体相交。需注意:1)使用误差控制避免浮点精度问题;2)反射点必须位于光线前进方向;3)输出最后反射点坐标,保留4位小数。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<set> #include<map> #include<algorithm> const int maxn = 1e2; const double pi = acos(-1.0); const double eps = 1e-5; using namespace std; // 加法误差 double add(double a, double b) { if (fabs(a + b) < eps) return 0; return a + b; } // 向量运算 struct P { double x, y, z; P() {} P(double x, double y, double z) : x(x), y(y), z(z) {} P operator + (P p) { return P(add(x, p.x), add(y, p.y), add(z, p.z)); } P operator - (P p) { return P(add(x, -p.x), add(y, -p.y), add(z, -p.z)); } P operator * (double d) { return P(x * d, y * d, z * d); } // 点乘 double dot(P p) { return add(add(x * p.x, y * p.y), z * p.z); } // 面积 double area(P p) { double dx = add(y * p.z, -z * p.y); double dy = -add(x * p.z, -z * p.x); double dz = add(x * p.y, -y * p.x); double s = add(add(dx * dx, dy * dy), dz * dz); return sqrt(s); } // 向量模长 double lenth() { return sqrt(add(add(x * x, y * y), z * z)); } // 单位向量 P unit() { return P(x, y, z) * (1 / lenth()); } // 向量p1-p在向量p1-p2上的投影模长 double prj_len(P p1, P p2) { P p(x, y, z); return (p - p1).dot((p2 - p1).unit()); } // 在p1-p2上的投影(垂足) P prj(P p1, P p2) { P p(x, y, z); return p1 + (p2 - p1).unit() * p.prj_len(p1, p2); } // 关于p1-p2的对称点 P sym(P p1, P p2) { P p(x, y, z); P e = p.prj(p1, p2); return e * 2 - p; } }; struct dis { P p; double d; int ind; dis() {} dis(P p, double d, int ind) : p(p), d(d), ind(ind) {} }; bool operator < (dis a, dis b) { return a.d < b.d; } int main() { int n, num; double r[maxn]; P st, a[maxn], s; dis df[maxn]; while (scanf("%d", &n) && n) { int m = -1; scanf("%lf %lf %lf", &s.x, &s.y, &s.z); st.x = st.y = st.z = 0; for (int i = 0; i < n; i++) { scanf("%lf %lf %lf %lf", &a[i].x, &a[i].y, &a[i].z, &r[i]); } while (1) { num = 0; P next = st + s, toy; for (int i = 0; i < n; i++) { if (i == m) continue; P e = a[i].prj(st, next); P ss = e - a[i]; double d = ss.lenth(); if (d > r[i] || !add(r[i], -d)) continue; // 相切或相离 double dx = s.x, dy = s.y, dz = s.z; double Dx = add(st.x, -a[i].x), Dy = add(st.y, -a[i].y), Dz = add(st.z, -a[i].z); // A*t^2 + B*t + C = 0 double A = add(add(dx * dx, dy * dy), dz * dz); double B = 2 * add(add(dx * Dx, dy * Dy), dz * Dz); double C = add(add(Dx * Dx, Dy * Dy), add(Dz * Dz, -r[i] * r[i])); double lf = add(B * B, -4 * A * C); if (lf <= 0) continue; double dd = sqrt(lf); double t1 = add(-B, dd) / 2 / A, t2 = add(-B, -dd) / 2 / A; P p1 = P(add(t1 * dx, st.x), add(t1 * dy, st.y), add(t1 * dz, st.z)); double d1 = (p1 - st).lenth(); P p2 = P(add(t2 * dx, st.x), add(t2 * dy, st.y), add(t2 * dz, st.z)); double d2 = (p2 - st).lenth(); if (s.dot(p1 - st) > 0) df[num++] = dis(p1, d1, i); if (s.dot(p2 - st) > 0) df[num++] = dis(p2, d2, i); } if (!num) break; sort(df, df + num); m = df[0].ind; P e = st.sym(a[df[0].ind], df[0].p); st = df[0].p; s = e - st; P p2 = e; } printf("%.4lf %.4lf %.4lf\n", st.x, st.y, st.z); } return 0; }
- 1
信息
- ID
- 2935
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者