链接 J. Transform
题意
给出两个点求第二个点绕从原点到第一个点这条轴旋转 r r r 或 − r -r −r ,得到两个点,输出 z z z 坐标最大的那个点;
思路
刚开始想的旋转坐标轴,然后旋转点,再旋转回去,过于复杂了;
这个题用 罗德里格斯旋转公式 可以直接秒
v
′
⃗
=
v
⃗
+
s
i
n
θ
∗
k
⃗
×
v
⃗
+
(
1
−
c
o
s
θ
)
∗
k
⃗
×
(
k
⃗
×
v
⃗
)
\vec{v'}=\vec{v} + sin\theta*\vec{k}\times\vec{v} + (1-cos\theta) * \vec{k} \times(\vec{k}\times\vec{v})
v′=v+sinθ∗k×v+(1−cosθ)∗k×(k×v)
罗德里格斯旋转公式具体证明可以看大佬博客QWQ
AC代码
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair <int,int> PII;
const int N = 4000010;
const ll mod = 998244353;
const double pi = 3.1415926535897932;
const double eps = 1e-10;
int T;
double A, B, C, x, y, z, r;
struct Point{
double a, b, c;
Point (double aa, double bb, double cc) {
a = aa, b = bb, c = cc;
}
};
Point operator +(Point a, Point b) {
return Point(a.a + b.a, a.b + b.b, a.c + b.c);
}
Point operator *(Point a, double u) {
return Point(a.a * u, a.b * u, a.c * u);
}
double operator *(Point a, Point b) {
return a.a * b.a + a.b * b.b + a.c * b.c;
}
Point operator ^(Point a, Point b) {
return Point(a.b * b.c - b.b * a.c, a.c * b.a - b.c * a.a, a.a * b.b - a.b * b.a);
}
double get_dist(Point a) {
return sqrt(a.a * a.a + a.b * a.b + a.c * a.c);
}
int dcmp(double x, double y)
{
if (fabs(x - y) < eps) return 0;
if (x < y) return -1;
return 1;
}
Point get_v(Point k, Point a, double angle) {
double co = cos(angle), si = sin(angle);
return a + ((k * si) ^ a) + ((k * (1 - co)) ^ (k ^ a));
}
int main()
{
cin >> T;
while (T --) {
cin >> A >> B >> C >> x >> y >> z >> r;
Point k = Point(A, B, C);
r = r / 180 * pi;
double res = get_dist(k);
k = Point(A / res, B / res, C / res);
Point v = {x, y, z};
Point x = get_v(k, v, r);
Point y = get_v(k, v, -r);
if (dcmp(x.c, y.c) == 1) printf("%.8lf %.8lf %.8lf\n", x.a, x.b, x.c);
else printf("%.8lf %.8lf %.8lf\n", y.a, y.b, y.c);
}
return 0;
}