1013: [JSOI2008]球形空间产生器sphere
Description
有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
Input
第一行是一个整数n(1<=N=10)。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。
Output
有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
Sample Input
2
0.0 0.0
-1.0 1.0
1.0 0.0
Sample Output
0.500 1.500
通过每一个点到圆心的距离相等可以列出 n <script type="math/tex" id="MathJax-Element-1">n</script>个方程。用高斯消元解就可以了。
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
const int N = 30;
const double eps = 1e-9;
double mat[N][N];
int n;
double a[N], ans[N];
double x;
template<typename T>
inline T Abs(T x) {
return x < 0 ? -x : x;
}
void Gauss(void) {
int pos;
for (int i = 1; i < n; i++) {
pos = i;
for (int j = i + 1; j <= n; j++)
if (Abs(mat[j][i]) > Abs(mat[pos][i]) + eps) pos = j;
if (pos != i)
for (int j = i; j <= n + 1; j++)
swap(mat[i][j], mat[pos][j]);
for (int j = i + 1; j <= n; j++)
for (int k = n + 1; k >= i; k--)
mat[j][k] = mat[i][k] * mat[j][i] / mat[i][i] - mat[j][k];
}
for (int i = n; i; i--) {
ans[i] = mat[i][n + 1];
for (int j = i + 1; j <= n; j++)
ans[i] -= ans[j] * mat[i][j];
if (mat[i][i]) ans[i] /= mat[i][i];
else ans[i] = 0;
}
}
int main(void) {
freopen("1.in", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lf", &a[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
scanf("%lf", &x);
mat[i][j] = 2.0 * (x - a[j]);
mat[i][n + 1] += x * x - a[j] * a[j];
}
Gauss();
for (int i = 1; i < n; i++) printf("%.3lf ", ans[i]);
printf("%.3lf\n", ans[n]);
return 0;
}