球形空间产生器
题目链接:ybt金牌导航8-2-1 / luogu P4035
题目大意
在一个 n 维的地方有 n+1 个点在一个 n 维球的球面上,要你求这个 n 维球的球心坐标。
球心到球面的距离相等,然后距离就是像勾股定理一样,根号里面有多少维就弄多少个。
思路
这题我们先看到距离相等这个东西,那我们考虑列式子。
那它是形如这样的:(设球心坐标为 ( m 1 , m 2 , . . . , m n ) (m_1,m_2,...,m_n) (m1,m2,...,mn))
( m 1 − a 1 ) 2 + ( m 2 − a 2 ) 2 + . . . + ( m n − a n ) 2 = ( m 1 − b 1 ) 2 + ( m 2 − b 2 ) 2 + . . . + ( m n − b n ) 2 (m_1-a_1)^2+(m_2-a_2)^2+...+(m_n-a_n)^2=(m_1-b_1)^2+(m_2-b_2)^2+...+(m_n-b_n)^2 (m1−a1)2+(m2−a2)2+...+(mn−an)2=(m1−b1)2+(m2−b2)2+...+(mn−bn)2
然后你可以一直列,不同的你可以列 n n n 个。
然后你看到 n n n 个未知数 n n n 个方程,你会想到用高斯消元。
但是它有平方啊!
其实你把式子化开,你会发现未知数的二次项会被消掉。
会变成这样:
− a 1 × m 1 × 2 + a 1 2 − a 2 × m 2 × 2 + a 2 2 − . . . − a n × m n × 2 + a n 2 = − b 1 × m 1 × 2 + b 1 2 − b 2 × m 2 × 2 + b 2 2 − . . . − b n × m n × 2 + b n 2 -a_1\times m_1\times2+a_1^2-a_2\times m_2\times2+a_2^2-...-a_n\times m_n\times2+a_n^2=-b_1\times m_1\times2+b_1^2-b_2\times m_2\times2+b_2^2-...-b_n\times m_n\times2+b_n^2 −a1×m1×2+a12−a2×m2×2+a22−...−an×mn×2+an2=−b1×m1×2+b12−b2×m2×2+b22−...−bn×mn×2+bn2
− a 1 × m 1 × 2 + b 1 × m 1 × 2 − a 2 × m 2 × 2 + b 2 × m 2 × 2 − . . . − a n × m n × 2 + b n × m n × 2 = − a 1 2 + b 1 2 − a 2 2 + b 2 2 − . . . − a n 2 + b n 2 -a_1\times m_1\times2+b_1\times m_1\times2-a_2\times m_2\times2+b_2\times m_2\times2-...-a_n\times m_n\times2+b_n\times m_n\times2=-a_1^2+b_1^2-a_2^2+b_2^2-...-a_n^2+b_n^2 −a1×m1×2+b1×m1×2−a2×m2×2+b2×m2×2−...−an×mn×2+bn×mn×2=−a12+b12−a22+b22−...−an2+bn2
(每个式子都这样弄一下,就有 n n n 个这样的式子)
那你就可以把式子弄高斯消元,也就得出答案了。
我这里是一遍统一拿第一个点,另一边就各是不同的点。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n, maxx;
double last[21], f[21][21];
double maxn, x;
double abss(double x) {
if (x < 0) return -x;
return x;
}
void gauss(int n) {
//高斯消元
for (int i = 1; i <= n; i++) {
maxn = -1e9;
for (int j = i; j <= n; j++)
if (maxn < abss(f[j][i])) {
maxn = abss(f[j][i]);
maxx = j;
}
for (int j = 1; j <= n + 1; j++)
swap(f[i][j], f[maxx][j]);
double tmp = f[i][i];
for (int j = 1; j <= n + 1; j++)
f[i][j] /= tmp;
for (int j = 1; j <= n; j++) {
if (i == j) continue;
tmp = f[j][i];
for (int k = 1; k <= n + 1; k++)
f[j][k] -= tmp * f[i][k];
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lf", &x);
last[i] -= 2 * x;//根据两个距离相等列数字
last[n + 1] -= x * x;//这个是给出一遍
}
for (int i = 2; i <= n + 1; i++) {
for (int j = 1; j <= n; j++) {
scanf("%lf", &x);
f[i - 1][j] += 2 * x;//补上另一边
f[i - 1][j] += last[j];
f[i - 1][n + 1] += x * x;
}
f[i - 1][n + 1] += last[n + 1];
}
gauss(n);
for (int i = 1; i <= n; i++)
printf("%.3lf ", f[i][n + 1] / f[i][i]);
return 0;
}