题意描述
洛谷链接
有一个球形空间产生器能够在 \(n\)
维空间中产生一个坚硬的球体。现在,你被困在了这个 \(n\) 维球体中,你只知道球面上 \(n + 1\)
个点的坐标,你需要以最快的速度确定这个 \(n\)
维球体的球心坐标,以便于摧毁这个球形空间产生器。
解题思路
对于本题,我们可以感性感知到这道题是高斯消元。于是我们可以通过距离公式推出下列式子:
\[
\sum_{j = 1}^{n} (a_{i, j} - x_j)^2 = \text{dis} \quad i \in [1, n] \cap
\mathbb{Z}
\]
其中 \(\text{dis}\) 为常量。
对于该式化简会出现二次项,不好计算,我们需要把二次项化掉,同时化掉
\(\text{dis}\)。
于是我们可以将相邻两项作差,得到下列式子:
\[
\sum_{j = 1}^{n} ( a_{i, j}^2 - a_{i + 1, j}^2 - 2(a_{i, j} - a_{i + 1,
j})x_j ) = 0 \quad i \in [1, n] \cap \mathbb{Z}
\]
然后移项得到下列式子:
\[
\sum_{j = 1}^{n} 2(a_{i, j} - a_{i + 1})x_j = \sum_{j = 1}^{n} (a_{i,
j}^2 - a_{i + 1, j}^2) \quad i \in [1, n] \cap \mathbb{Z}
\]
由于 \(a_{i, j}\),\(n\) 为常量,故 \(x_j\) 可用高斯消元求解,最后得解。
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <cstdio> #include <iostream>
const int MAXN = 10;
int n; double pos[MAXN + 2][MAXN + 1], a[MAXN + 1][MAXN + 2];
void gauss() { for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n + 1; j++) a[i][j] /= a[i][i]; a[i][i] = 1;
for (int j = i + 1; j <= n; j++) { for (int k = i + 1; k <= n + 1; k++) { a[j][k] -= a[i][k] * a[j][i] / a[i][i]; } a[j][i] = 1; } } }
void solve() { for (int i = n; i > 1; i--) { for (int j = 1; j < i; j++) { a[j][n + 1] -= a[i][n + 1] * a[j][i] / a[i][i]; a[j][i] = 0; } } }
void init() { for (int i = 1; i <= n; i++) { a[i][n + 1] = 0; for (int j = 1; j <= n; j++) { a[i][j] = 2 * (pos[i][j] - pos[i + 1][j]); a[i][n + 1] += pos[i][j] * pos[i][j] - pos[i + 1][j] * pos[i + 1][j]; } } }
int main() {
std::cin >> n;
for (int i = 1; i <= n + 1; i++) { for (int j = 1; j <= n; j++) { std::cin >> pos[i][j]; } }
init();
gauss();
solve();
for (int i = 1; i <= n; i++) { printf("%.3f ", a[i][n + 1]); } std::cout << std::endl;
return 0; }
|